How to Export Non Clustered VM’S and Import Them to CSV Shares on 2008 R2 Cluster

So I have been asked a few times a process of how to take a Windows Server 2008 R2 Enterprise Hyper-V Server and reconfigure it into a Windows 2008 R2 Failover Cluster with CSV’s running the Hyper-V Application.  So I decided to write this process here in this blog.  As you can see from the picture below we have one child partition that is running on Windows Server 2008 R2. 

Note:  In this example I will be clustering a Windows 2008 R2 Enterprise Core server.  I have connected to the Windows Server 2008 R2 Core Server through another server.



So here you can see I have a VM that is listed in my Hyper-V and that the VM is off.clip_image003

So the first thing to do is to shut down the VM’s and export them. To ensure that if anything happens you have a good backup of the VM’s.


Save the VM out on the network, or any other disk that will not be clustered.  Once you have ensured that all the VM’s are backed up and in a safe location we will need to export the configuration file that we will use to import the VM back into Hyper-V. 

To do this we will have to run a script.  The script that will be used is listed below:

Option Explicit


Dim HyperVServer

Dim VMName

Dim ExportPath

Dim WMIService

Dim Msvm_VirtualSystemManagementService

Dim query

Dim vm

Dim InParam

Dim exportSettingData

Dim OutParam

Dim Job


‘Prompt for the Hyper-V Server to use

HyperVServer = InputBox("Specify the Hyper-V Server to export the virtual machine from:")


‘Get name for the virtual machine to export

VMName = InputBox("Specify the name of the virtual machine to export:")


‘Get location for the exported virtual machine

ExportPath = InputBox("Specify the location to export the virtual machine configuration to:")


‘Get an instance of the WMI Service in the virtualization namespace.

Set WMIService = GetObject("winmgmts:\\" & HyperVServer & "\root\virtualization")


‘Get the Msvm_VirtualSystemManagementService object

Set Msvm_VirtualSystemManagementService = WMIService.ExecQuery("Select * from Msvm_VirtualSystemManagementService").ItemIndex(0)


‘Get the virtual machine object

query = "select * from Msvm_ComputerSystem where ElementName = ‘" & VMName & "’"

Set vm = WMIService.ExecQuery(query).ItemIndex(0)


‘Setup the input parameter list

Set InParam = Msvm_VirtualSystemManagementService.Methods_("ExportVirtualSystemEx").InParameters.SpawnInstance_()

InParam.ComputerSystem = vm.Path_.Path


Set exportSettingData = (vm.Associators_("Msvm_SystemExportSettingData", "Msvm_VirtualSystemExportSettingData")).ItemIndex(0) 


exportSettingData.CopyVmStorage = False   

exportSettingData.CopyVmRuntimeInformation = true   

exportSettingData.CreateVmExportSubdirectory = true   

exportSettingData.CopySnapshotConfiguration = 0   


InParam.ExportSettingData = exportSettingData.GetText_(1)

InParam.ExportDirectory = ExportPath


‘Execute the method and store the results in OutParam

Set OutParam = Msvm_VirtualSystemManagementService.ExecMethod_("ExportVirtualSystemEx", InParam)


‘Check to see if the job completed synchronously

if (OutParam.ReturnValue = 0) then

   Wscript.Echo "The virtual machine has been exported."

elseif (OutParam.ReturnValue <> 4096) then

   Wscript.Echo "The virtual machine has not been exported."



   ‘Get the job object

   set Job = WMIService.Get(OutParam.Job)


    ‘Wait for the job to complete (3 == starting, 4 == running)

   while (Job.JobState = 3) or (Job.JobState = 4)

      Wscript.Echo "Exporting virtual machine. " & Job.PercentComplete & "% complete"



      ‘Refresh the job object

      set Job = WMIService.Get(OutParam.Job)



   ‘Provide details if the job fails (7 == complete)

   if (Job.JobState <> 7) then

      Wscript.Echo "The virtual machine has not been exported."

      Wscript.Echo "ErrorCode:" & Job.ErrorCode

      Wscript.Echo "ErrorDescription:" & Job.ErrorDescription


      Wscript.Echo "The virtual machine has been exported."

   end If

end if


NOTE: copy the code listed above and save it to the computer.  In my example I saved it as exportconfig.vbs.

So to run this script we will need to execute it from the CMD window on the Windows Server 2008 R2 Core server.  I executed the script by typing exportconfig.vbs and pressing enter.  There will be a few popup boxes that you will need to answer.  Let’s take a look at them now:




Here you will want to specify the Hyper-V Parent server.  In this case it’s Hyper-V-1.  Press “OK” after you enter your Hyper-V Parent server name.


Test VM



Next you will have to give the name of the VM that you want to export the configuration from.  In my case it is Test VM.  Press “ok” after you have identified the VM that you want to export.

C:\Configonly\Test VM



The next popup will ask you for a location to save the VM configuration file to.  In my case I created a folder on C, called configonly, and saved the configuration file there.  Press “ok” after you enter a path to save the export configuration file to.


You then should see a few popups that let you know that the configuration file is exporting.  Click ok here to continue.


Finally the configuration file has been exported.

Note:  You will have to run this script for every VM that you want to export from the Hyper-V server.


Now that the VM’s are exported you can Cluster the two (or more) nodes together.  Again I will be using another server to run the Failover Cluster Manager to perform the cluster of the two nodes (I am only cluster 2 nodes in my example).




Click on create a Cluster.  And follow the wizard. 

clip_image014Click next.


Add the server names that are to be clustered together.


Here you can see that I have added both of my server’s names here.  Once you have all the server names added to the selected servers column click next.


Next thing to do is to give the cluster a name, and then click next.


This is the confirmation screen, just click next…

clip_image024 Wait for the cluster to be configured.


And finally we have a cluster. Click on finished.




The next thing we need to do is to setup the Cluster Shared Volumes.  To do this you will select “Enable Cluster Shared Volumes…” link from the Failover Cluster Manager.  To see this option you must have the cluster name highlighted.


Once you click on the link you will get a warning message informing you of the following:


Select “I have read the above notice” and then click “ok”


You will now see a new area listed under the cluster.  This is the Cluster Shared Volumes.  Once you have added the clustered storage you can then add that storage to “Cluster Shared Volumes”.  To do this you select “Cluster Shared Storage” and then click the “add storage” link under the actions pane on the right hand side.  A new window will pop up and list the disk that are currently in the cluster storage area. 


Place a check mark next to the storage you want to add to the “Cluster Shared Storage” area and then select “OK”.


Click ok to add the selected storage to the cluster shared volumes.

You should then see the storage added to the “Cluster Shared Volumes” location.


Note: at this point any drive letter that was assigned to the disk that was added to the cluster shared volumes is now removed.  To access the disk you will need to browse c:\clusterstorage\volume#\.  Also the order that the disk were listed back when you added them to the cluster shared storage is the way that the volumes will be displayed under the c:\clusterstorage directory.



So what is the next thing that we need to do…well we need to delete the VM from the Hyper-v Manager.  To do this you will select the VM machine from the Hyper-V Manager window.


 Next you will click on the delete option on the right hand side of the Hyper-v Manager window.


This will remover the VM from the Hyper-V Manager. This does not delete the VHD file that was associated with the VM.


As you can see the VM is now missing.  But not to worry it soon will be back.  Next thing that we need to do is to run the Import script.  Copy the script is listed below:

option explicit


Dim objWMIService

Dim managementService

Dim switchService

Dim fileSystem


const JobStartIng = 3

const JobRunnIng = 4

const JobCompleted = 7

const wmiStarted = 4096

const wmiSuccessful = 0





‘ MaIn


Sub MaIn()

    Dim computer, objArgs, importDirectory, generateNewID, tempSourceResourcePaths, sourceResourcePaths(), Index, resourcePaths, path, i, j


    Set objArgs = WScript.Arguments.Named

    If WScript.Arguments.Count = 2 Then

        If objArgs.Exists("ImportDirectory") Then

           importDirectory = objArgs.Item("ImportDirectory")


           WScript.Echo "ImportDirectory argument is not provided, Please refer the usage section for more inFormation on the arguments"


        End If

        If objArgs.Exists("ResourcePaths") Then

           resourcePaths = objArgs.Item("ResourcePaths")

                       tempSourceResourcePaths = Split(resourcePaths, ";")

                       i = 0

                       For j=0 to UBound(tempSourceResourcePaths)

                If tempSourceResourcePaths(j) <> "" Then

                    If IsNull(tempSourceResourcePaths(j)) <> true Then

                        ReDim Preserve sourceResourcePaths(i)

                        sourceResourcePaths(i) = tempSourceResourcePaths(j)

                        i = i + 1

                    End If

                End If


           WScript.Echo "Resource Paths"

           For Each path In sourceResourcePaths

                       WScript.Echo path



           WScript.Echo "ResourcePaths argument is not provided, Please refer the usage section for more inFormation on the arguments"


        End If


        WScript.Echo "Number of arguments does not match, Please refer the usage section for more information on the arguments"


    End If



    Set fileSystem = Wscript.CreateObject("ScriptIng.FileSystemObject")

    computer = "."

    Set objWMIService = GetObject("wInmgmts:\\" & computer & "\root\virtualization")

    Set managementService = objWMIService.ExecQuery("select * from Msvm_VirtualSystemManagementService").ItemIndex(0)

    Set switchService = objWMIService.ExecQuery("select * from Msvm_VirtualSwitchManagementService").ItemIndex(0)


    If ImportVirtualSystemEx(importDirectory, (sourceResourcePaths)) Then

        WriteLog "Done"



        WriteLog "ImportVirtualSystemEx Failed."


    End If

End Sub




‘ GetVirtualSystemImportSettIngData from a directory


Function GetVirtualSystemImportSettIngData(importDirectory)


    Dim objInParam, objOutParams   


    Set objInParam = managementService.Methods_("GetVirtualSystemImportSettIngData").InParameters.SpawnInstance_()

    objInParam.ImportDirectory = importDirectory


    Set objOutParams = managementService.ExecMethod_("GetVirtualSystemImportSettIngData", objInParam)


    If objOutParams.ReturnValue = wmiStarted Then

        If (WMIJobCompleted(objOutParams)) Then

            Set GetVirtualSystemImportSettIngData = objOutParams.ImportSettIngData

        End If

    ElseIf objOutParams.ReturnValue = wmiSuccessful Then

        Set GetVirtualSystemImportSettIngData = objOutParams.ImportSettIngData


        WriteLog Format1("GetVirtualSystemImportSettIngData failed with ReturnValue {0}", objOutParams.ReturnValue)

    End If


End Function


‘ ImportVirtualSystem from a directory


Function ImportVirtualSystemEx(importDirectory, sourceResourcePaths)


    Dim objInParam, objOutParams

    Dim newDataRoot

    Dim importSettIngData

    Dim currentResourcePaths


    ImportVirtualSystemEx = false

    Set objInParam = managementService.Methods_("ImportVirtualSystemEx").InParameters.SpawnInstance_()

    objInParam.ImportDirectory = importDirectory


    Set importSettIngData = GetVirtualSystemImportSettIngData(importDirectory)

    currentResourcePaths = importSettIngData.CurrentResourcePaths

    Call OrderResourcePaths(currentResourcePaths, sourceResourcePaths)

    importSettIngData.GenerateNewId = false

    importSettIngData.CreateCopy = false

    importSettIngData.SourceResourcePaths = sourceResourcePaths

    importSettIngData.CurrentResourcePaths = currentResourcePaths   


    objInParam.ImportSettIngData = importSettIngData.GetText_(1)


    Set objOutParams = managementService.ExecMethod_("ImportVirtualSystemEx", objInParam)


    If objOutParams.ReturnValue = wmiStarted Then

        If (WMIJobCompleted(objOutParams)) Then

            ImportVirtualSystemEx = true

        End If

    ElseIf objOutParams.ReturnValue = wmiSuccessful Then

        ImportVirtualSystemEx = true


        WriteLog Format1("ImportVirtualSystemEx failed with ReturnValue {0}", objOutParams.ReturnValue)

    End If


End Function




‘ ImportVirtualSystem from a directory


Function OrderResourcePaths(currentResourcePaths, sourceResourcePaths)

    Dim resourcePathLength, newCurrentResourcePaths(), newSourceResourcePaths(), vhdName, pathNames, pos, index, initialIndex, i, j   

    If UBound(sourceResourcePaths) >= UBound(currentResourcePaths) Then

        resourcePathLength = UBound(sourceResourcePaths)


        WScript.Echo "Number of entries in the SourceResourcePaths and the CurrentResourcePaths are not matching , Please refer the usage section for more information on the arguments"


    End If

    index = 0

    For i=0 to resourcePathLength

        initialIndex = index

        pathNames = split(sourceResourcePaths(i), "\",-1,1)

        vhdName = pathNames(UBound(pathNames))

        For j=0 to UBound(currentResourcePaths)

            pos = Instr(1,currentResourcePaths(j),vhdName,1)

            If pos <> 0 Then

                ReDim Preserve newCurrentResourcePaths(index)               

                newCurrentResourcePaths(index) = currentResourcePaths(j)

                ReDim Preserve newSourceResourcePaths(index)  

                newSourceResourcePaths(index) = sourceResourcePaths(i)

                index = index + 1

                Exit For

            End If


        If initialIndex = index Then

            ReDim Preserve newCurrentResourcePaths(index)               

            newCurrentResourcePaths(index) = sourceResourcePaths(i)

            ReDim Preserve newSourceResourcePaths(index)  

            newSourceResourcePaths(index) = sourceResourcePaths(i)

            index = index + 1

        End If


    currentResourcePaths = newCurrentResourcePaths

    sourceResourcePaths = newSourceResourcePaths

End Function



‘ Handle wmi Job object


Function WMIJobCompleted(outParam)


    Dim WMIJob, jobState


    Set WMIJob = objWMIService.Get(outParam.Job)


    WMIJobCompleted = true


    jobState = WMIJob.JobState


    while jobState = JobRunnIng or jobState = JobStartIng

        WriteLog Format1("In progress… {0}% completed.",WMIJob.PercentComplete)


        Set WMIJob = objWMIService.Get(outParam.Job)

        jobState = WMIJob.JobState



    If (jobState <> JobCompleted) Then

        WriteLog Format1("ErrorCode:{0}", WMIJob.ErrorCode)

        WriteLog Format1("ErrorDescription:{0}", WMIJob.ErrorDescription)

        WMIJobCompleted = false

    End If


End Function



‘ Create the console log files.


Sub WriteLog(lIne)

    Dim fileStream

    Set fileStream = fileSystem.OpenTextFile(".\ImportVM.log", 8, true)

    WScript.Echo lIne

    fileStream.WriteLIne lIne



End Sub



‘ The strIng FormatIng functions to avoid strIng concatenation.


Function Format1(myStrIng, arg0)

    Format1 = Replace(myStrIng, "{0}", arg0)

End Function



‘ The Usage function to convey how to call the script.


Sub Usage()

    WScript.Echo "Usage: cscript ImportVM.vbs /ImportDirectory:importDirectoryName /ResourcePaths:CurrentResourcePaths"

    WScript.Echo "/ImportDirectory: Directory from where the virtual MachIne will be imported from."

    WScript.Echo "/ResourcePaths: The comma separated list of Current Resource Paths. The Former list of Resource Paths can be obtained by executIng "

    WScript.Echo "script GetImportSettIngsData. If there is any change in the paths fix it up and pass it as an argument to this script."

    WScript.Echo "Provide multiple paths in a comma separated way. Like /ResourcePaths: ""C:\a.vhd"";""C:\b.vhd"";""D:\abc.vhd"""


End Sub


So when we execute this script we need to do it from a CMD prompt so we can add some switches to it when it runs.  So you will need to do this from the Windows Server 2008 R2 core machine.  So the switches that we will be passing are importdirectory and resourcepaths.  ImportDirectory is the directory where the configuration file was exported to.  In my case it was c:\configonly\testvm.  The resourcepaths switch is where the VHD has been moved to.  In my case it will be located in the C:\clusterstorage\volume1\vm’s\test vm\test vm\test vm.vhd.  so when we run this with the switches in the CMD prompt window on Windows Server 2008 R2 it looks something like:


Note: this information can be found in KB957256 (

Once you hit enter you should then see a few popup windows that look like:


Click ok here…


Click ok here…


Click ok here…

The virtual machine has been imported.



And wow…finally done!  Click ok

Now let’s take a look back in Hyper-V manager…


You can see here that our VM is listed again in Hyper-V Manager.

Now we need to cluster the VM.  To do this open up Failover Cluster Manager


Then right click on Services and Application on the left hand side.


Select Configure a Service or Application…

This will open up a new wizard called High Availability Wizard


Click Next…


Then select the Virtual Machine option and then click next.


That will bring up a list of VM’s that are on the node.  You want to place a check mark next to the VM that you want to cluster and then click next.


That brings up the confirmation window…click next.


Yahoo!!! We have a finish button.  You can view the report for a list of warning or errors….but I am going to click finished.

Note: you will get a warning on the virtual machine due to CSV configuration…this is expected.

Once again back to Failover Cluster Manager to see the VM


Great job it is present in the Failover Cluster Manager.  Now to bring the VM online.


Looking Very nice here.  Now test failover and ensure that everything is working well. 


I hope that the information found in this article is helpful.

Keith Hill
Support Escalation Engineer
Microsoft Enterprise Platforms Support