locked
PowerShell copy and delete question RRS feed

  • Question

  • I have a script that I downloaded on the net and needed to modify a couple of items. I have bolded the three lines in question and comented them below.
    Here is the script:

    ##
    ##    Create a backup of all the vm's
    ##

    $dest = "D:\VMbackup"
    $dest2 = "D:\TapeBackup"
    $Date = (Get-Date).toString('ddMMyyyy')
    $Now = (Get-Date -Format ddMMyyy).AddDays(-21) <- powershell does not like this, but I not know how else to do it.
    $VM_Service = get-wmiobject -namespace root\virtualization Msvm_VirtualSystemManagementService
    $ListofVMs = get-wmiobject -namespace root\virtualization Msvm_ComputerSystem -filter  "ElementName <> Name"  

    foreach ($VM in [array] $ListOfVMs)
    {
        $VMReturnState = $VM.EnabledState
        $VMName = $VM.ElementName

        if (($VM.EnabledState -eq 2) -or ($VM.EnabledState -eq 32768) -or ($VM.EnabledState -eq 32770))
        {
            $VM.RequestStateChange(32769)
            echo "Saving the state of $VMName"
        }

        while (!($VM.EnabledState -eq 32769) -and !($VM.EnabledState -eq 3))
        {
            Start-Sleep(1)
            $VM = get-wmiobject -namespace root\virtualization -Query "Select * From Msvm_ComputerSystem Where ElementName='$VMName'"
        }


        if ([IO.Directory]::Exists("$dest\TmpDir\$VMName"))
        {
            [IO.Directory]::Delete("$dest\TmpDir\$VMName", $True)
        }

        echo "Exporting the VM"
        $status = $VM_Service.ExportVirtualSystem($VM.__PATH, $True, "$dest\TmpDir")
           
        if ($status.ReturnValue -eq 4096)
        {
            $job = [Wmi]$status.Job   
       
            while (!($job.PercentComplete -eq 100) -and ($job.ErrorCode -eq 0))
            {
                Start-Sleep(5)
                $job = [Wmi]$status.Job   
                echo $job.PercentComplete
            }
        }


        ##    Store the files on in a temp directory before moving them to their location and then remove the old files.

        if ([IO.Directory]::Exists("$dest\$VMName"))
        {
            [IO.Directory]::Move("$dest\$VMName", "$dest\$VMName-OldTmpDir")
            [IO.Directory]::Copy("$dest\TmpDir\$VMName", "$dest2\$VMName") <- make a copy of this folder before move and put in another folder
            [IO.Directory]::Move("$dest\TmpDir\$VMName", "$dest\$VMName-$Date")
            [IO.Directory]::Delete("$dest\$VMName-$Now", $True) <- Delete the folder it the folder+date is equal to 21 days
            [IO.Directory]::Delete("$dest\$VMName-OldTmpDir", $True)
        }
        else
        {
            [IO.Directory]::Move("$dest\TmpDir\$VMName", "$dest\$VMName-$DateD")
        }
       
        echo "Done with $VMName"
        $VM.RequestStateChange($VMReturnState)
    }
    Thursday, July 2, 2009 8:41 PM

Answers

  • Hi,

    Regarding your first bolded line : $Now = (Get-Date -Format ddMMyyy).AddDays(-21)
    Here (Get-Date -Format ddMMyyy) returns a string not a DateTime object. So there is no method called AddDays on this object. You have to modify date using AddDays before formating it.

    By Example : (Get-Date).AddDays(-21).ToString('ddMMyyyy')


    Then, prefer to use built-in Copy-Item , Remove-Item or Move-Item Cmdlets for copying, removing or moving items.

    Hope it helps.

    Grégory Schiro - PowerShell MVP - PowerShell & MOF
    • Proposed as answer by Grégory Schiro Friday, July 3, 2009 8:26 AM
    • Marked as answer by IamMred Friday, January 8, 2010 7:22 AM
    Friday, July 3, 2009 8:13 AM

All replies

  • Hi,

    Regarding your first bolded line : $Now = (Get-Date -Format ddMMyyy).AddDays(-21)
    Here (Get-Date -Format ddMMyyy) returns a string not a DateTime object. So there is no method called AddDays on this object. You have to modify date using AddDays before formating it.

    By Example : (Get-Date).AddDays(-21).ToString('ddMMyyyy')


    Then, prefer to use built-in Copy-Item , Remove-Item or Move-Item Cmdlets for copying, removing or moving items.

    Hope it helps.

    Grégory Schiro - PowerShell MVP - PowerShell & MOF
    • Proposed as answer by Grégory Schiro Friday, July 3, 2009 8:26 AM
    • Marked as answer by IamMred Friday, January 8, 2010 7:22 AM
    Friday, July 3, 2009 8:13 AM


  • Hello

    first one is easy to fix :)

    $Now = (Get-Date -Format ddMMyyy).AddDays(-21)
    should be
    $Now = (Get-Date).AddDays(-21)
    Cause the format function , causes the cmdlet to output a system.string instead of system.datetime, therefore you cannot run the adddays method (since it only exists on system.datetime).

    i am looking into the others.

    [IO.Directory]::Copy("$dest\TmpDir\$VMName", "$dest2\$VMName")

    I am not sure why u are using these methods directly?
    i would prefer to use the cmdlets provided by powershell.
    you can use this command instead of the abiove line


    Copy-Item -Recurse "$dest\TmpDir\$VMName" "$dest2\$VMName"

    [IO.Directory]::Delete("$dest\$VMName-$Now", $True)

    I am not sure what errors you get, but this command will not delete the folder if it is not empty.
    i would again use the cmdlet instead like this:

    Remove-Item -Recurse "$dest\$VMName-$Now"


    Good luck


    Best Regards
    Jakob Gottlieb svendsen
    Trainer/Consultant - Coretech A/S - Blog - MCT - MCTS - VB.NET - C#.NET - Powershell - VBScript
    Friday, July 3, 2009 8:20 AM
  • I have made the requested changes and for the most part it is working except for the rename-item part I have bolded below. I get this error
    Rename-Item : Cannot rename because the target specified is not a path.

    $dest1 = "D:\VMbackup"
    $dest2 = "D:\TapeBackup"
    $Date = (Get-Date).toString('ddMMyyyy')
    $Now = (Get-Date).AddDays(-21)
    $VM_Service = get-wmiobject -namespace root\virtualization Msvm_VirtualSystemManagementService
    $ListofVMs = get-wmiobject -namespace root\virtualization Msvm_ComputerSystem -filter  "ElementName <> Name"  

    foreach ($VM in [array] $ListOfVMs)
    {
     $VMReturnState = $VM.EnabledState
     $VMName = $VM.ElementName

     if (($VM.EnabledState -eq 2) -or ($VM.EnabledState -eq 32768) -or ($VM.EnabledState -eq 32770))
     {
      $VM.RequestStateChange(32769)
      echo "Saving the state of $VMName"
     }

     while (!($VM.EnabledState -eq 32769) -and !($VM.EnabledState -eq 3))
     {
      Start-Sleep(1)
      $VM = get-wmiobject -namespace root\virtualization -Query "Select * From Msvm_ComputerSystem Where ElementName='$VMName'"
     }


     if ([IO.Directory]::Exists("$dest1\TmpDir\$VMName"))
     {
      [IO.Directory]::Delete("$dest1\TmpDir\$VMName", $True)
     }

     echo "Exporting the VM"
     $status = $VM_Service.ExportVirtualSystem($VM.__PATH, $True, "$dest1\TmpDir")
      
     if ($status.ReturnValue -eq 4096)
     {
      $job = [Wmi]$status.Job 
     
      while (!($job.PercentComplete -eq 100) -and ($job.ErrorCode -eq 0))
      {
       Start-Sleep(5)
       $job = [Wmi]$status.Job 
       echo $job.PercentComplete
      }
     }


     ## Store the files on in a temp directory before moving them to their location and then remove the old files.

     if ([IO.Directory]::Exists("$dest1\$VMName"))
     {
      Move-Item "$dest1\$VMName", "$dest1\$VMName-OldTmpDir"
      Copy-Item -recurse -force "$dest1\TmpDir\$VMName", "$dest2\$VMName"
      Move-Item "$dest1\TmpDir\$VMName", "$dest1\$VMName-$Date"
      Remove-Item -recurse "$dest1\$VMName-$Now"
      Remove-Item -recurse "$dest1\$VMName-OldTmpDir"
     }
     else
     {
      Move-Item $dest1\TmpDir\$VMName $dest1\$VMName
      Rename-Item -path "$dest1\$VMName" -newname "$dest1\$VMName-$Now"
     }
     
     echo "Done with $VMName"
     $VM.RequestStateChange($VMReturnState)
    }

    Thanks for the help...I am very close now!

    Friday, September 11, 2009 6:23 PM