4

I built a script that mounts (attach) a VHD using Diskpart, cleans out some system files and then unmounts (detach) it. It uses a foreach loop and is suppose to clean multiple VHD using the same drive letter. However, after the 1st VHD it fails. I also noticed that when I try to manually attach a VHD with diskpart, diskpart succeeds, the Disk Manager shows the disk with the correct drive letter, but within the same PoSH instance, I can not connect (set-location) to that drive. If I do a manual diskpart when I 1st open PoSH, within that instance, I can attach and detach all I want and I get the drive letter every time, but the minute I run the script the a drive letter gets destroyed within the instance after use. Is there something I need to do to reset diskpart in the script? Here's a snippet of the script I'm using.

$test=""
    $Test2=""
    $MsgBoxObj = New-Object -ComObject wscript.shell
    $all = @()
    $obj = New-Object System.Collections.ArrayList 
    $hash = @{}
function Mount-VHD {
    [CmdletBinding()]
    param (
        [Parameter(Position=0,Mandatory=$true,ValueFromPipeline=$false)]
            [string]$Path,
        [Parameter(Position=1,Mandatory=$false,ValueFromPipeline=$false)]
            [string]$DL,
        [string]$DiskpartScript = "$env:SystemDrive\DiskpartScript.txt",
        [switch]$Rescan
    )

    begin {
        function InvokeDiskpart {
            Diskpart.exe /s $DiskpartScript
        }
        ## Validate Operating System Version ##
        if (Get-WmiObject win32_OperatingSystem -Filter "Version < '6.1'") {throw "The script operation requires at least Windows 7 or Windows Server 2008 R2."}
    }
    process{
        ## Diskpart Script Content ## Here-String statement purposefully not indented ## 
@"
$(if ($Rescan) {'Rescan'})
Select VDisk File="$Path" `nAttach VDisk 
Exit "@ | Out-File -FilePath $DiskpartScript -Encoding ASCII -Force
        InvokeDiskpart
Start-Sleep -Seconds 3  
@"
Select VDisk File="$Path"`nSelect partition 1 `nAssign Letter="$DL" 
Exit
"@ | Out-File -FilePath $DiskpartScript -Encoding ASCII -Force
        InvokeDiskpart
            }
    end {
        Remove-Item -Path $DiskpartScript -Force ; ""
        Write-Host "The VHD ""$Path"" has been successfully mounted." ; ""
    }
}
function Dismount-VHD {
    [CmdletBinding()]
    param (
        [Parameter(Position=0,Mandatory=$true,ValueFromPipeline=$false)]
            [string]$Path,
        [switch]$Remove,
        [switch]$NoConfirm,
        [string]$DiskpartScript = "$env:SystemDrive\DiskpartScript.txt",
        [switch]$Rescan
    )

    begin {
        function InvokeDiskpart {
            Diskpart.exe /s $DiskpartScript
        }

        function RemoveVHD {
            switch ($NoConfirm) {
                $false {
                    ## Prompt for confirmation to delete the VHD file ##
                    "" ; Write-Warning "Are you sure you want to delete the file ""$Path""?"
                    $Prompt = Read-Host "Type ""YES"" to continue or anything else to break"
                    if ($Prompt -ceq 'YES') {
                        Remove-Item -Path $Path -Force
                        "" ; Write-Host "VHD ""$Path"" deleted!" ; ""
                    } else {
                        "" ; Write-Host "Script terminated without deleting the VHD file." ; ""
                    }
                }
                $true {
                    ## Confirmation prompt suppressed ##
                    Remove-Item -Path $Path -Force
                    "" ; Write-Host "VHD ""$Path"" deleted!" ; ""
                }
            }
        }
        ## Validate Operating System Version ##
        if (Get-WmiObject win32_OperatingSystem -Filter "Version < '6.1'") {throw "The script operation requires at least Windows 7 or Windows Server 2008 R2."}
    }
    process{
    ## DiskPart Script Content ## Here-String statement purposefully not indented ## 
    @"
$(if ($Rescan) {'Rescan'})
Select VDisk File="$Path"`nDetach VDisk
Exit
"@ | Out-File -FilePath $DiskpartScript -Encoding ASCII -Force
        InvokeDiskpart
        [gc]::collect()
        Start-Sleep -Seconds 15
        reg unload hklm\DesktopVM 
        reg unload hklm\DesktopSoft

    }
    end {
        if ($Remove) {RemoveVHD}
        Remove-Item -Path $DiskpartScript -Force ; ""
        }

}
Function mount-it {param($source, $privatename)
#Import-Module "F:\Scripts\LJ_Cleanup\mount.psm1"
# Script to use a mounted VHD to clean off the LJ service footprint
$error.clear()
set-location I: 
$Test=$?

    If ($test -ne $true){

        [System.Windows.Forms.Application]::DoEvents()
        $localtest=hostname
        $localname=$source.substring(2,15)
        if ($localtest -ne $localname)
        {   
            net use N: $source
            $script:mountpoint="N:\$privatename"

            }
        else
        {
            $split1 = $source.split("/$")
            $split2 = $source.split("$")
            $locallocation = $split1[3] + ":" + $split2[1]
            $script:mountpoint="$locallocation\$privatename"
        }
            Mount-VHD  $mountpoint I
            $error.clear()
            set-location "I:\Windows"
            $Test=$?
        If ($test -eq $true){
            write-host "**Disk Mount Successful**"

            Return $mountpoint  
            [System.Windows.Forms.Application]::DoEvents()
            }
        else {
            write-host "**ALERT:  The Disk mounted has no bootable partition.  Please close application and check the Image.**"

            Dismount-VHD $mountpoint
            if ($mountpoint.substring(0,1) -eq "N")
            {
                net use N: /delete
            }
            Set-Location F:


            $Script:Cancelit=1
            Return $Cancelit

            }

            }
    else {
        Write-host "**ALERT:  There was a problem Mounting the vDisk.  Please close application and check the Disk Manager on the server to ensure the I: drive is available.**"

            $Script:Cancelit=1
            Return $Cancelit
        }

}#End Function
Function mount-Continue{param($location, $Disk, $server1) #Import-Module "F:\Scripts\LJ_Cleanup\mount.psm1"
# Script to use a mounted VHD to clean off the AppV service footprint
$error.clear()
set-location I:  $Test=$?

    If ($test -ne $true){
        net use /persistent:no
        #net use * /d

        write-host "Mounting VHD from $destination"
        $localtest=hostname
        if ($localtest -ne $server1)
        {   
            net use N: $location
            $Script:MC = "N:\$Disk"

            }
        else
        {
            $Script:MC = "F:\vdisks\$disk"

        }
        Mount-VHD $MC I
        $error.clear()
set-location "I:\Windows" $Test=$?

    If ($test -eq $true)
        {
            Write-host "**Disk Mount Successful**"
            Return $Disk  

            }
        else {
            Write-host "**ALERT:  The Disk mounted has no bootable partition.  Manually clean image and click ok to continue.**"

            $MsgBoxObj.Popup('**ALERT:  The Disk mounted has no bootable partition.  Manually clean image and click ok to continue.**')
            Return $Disk
            }

            }
    else {
        write-host "**ALERT:  There was a problem Mounting the vDisk.  Manually clean image and click ok to continue.**"
        $MsgBoxObj.Popup('**ALERT:  The Disk mounted has no bootable partition.  Manually clean image and click ok to continue.**')
        Return $Disk
        }

}#End Function
Function Dismount-it{
param ($Disk)
set-location F:
Dismount-VHD $disk
if ($Disk.substring(0,1) -eq "N")
{
    net use N: /delete
}
    $error.clear()
            set-location "I:\Windows"
            $Test=$?
        If ($test -ne $true)
        {
        Write-host " **Disk Successful Unmounted**"

        return

        }
    else {
        Write-host "**ALERT:  There was a problem unmounting the vDisk.  Please close application and troubleshoot.**"

        $Script:Cancelit=1
        Return $Cancelit
        }
}#End Function
Function Dismount-Continue{
set-location F:
Dismount-VHD $MC if ($MC.substring(0,1) -eq "N") {
    net use N: /delete

}           
    $error.clear()
            set-location "I:\Windows"
            $Test=$?
        If ($test -ne $true){
        Write-host " `r**Disk Successful Unmounted**"

        return

        }
    else {
        Write-host "**ALERT:  There was a problem unmounting the vDisk.  Manually clean image and click ok to continue.**"

        $MsgBoxObj.Popup('**ALERT:  There was a problem unmounting the vDisk.  Manually clean image and click ok to continue.**')
            Return $Disk
        }
}#End Function
Mount-it "\\server1pvs1\g$\vdisks" "image - private.vhd"
dir
Dismount-it $mountpoint
dir
Mount-it "\\server1pvs1\g$\vdisks" "image - private.vhd"
dir
Dismount-it $mountpoint

UPDATE: new-PSdrive doesn't allow you to mount a VHD (or atleast I haven't found a way). What I have found is that the problem I described above stems from using Test-path. Don't believe me, try this: Open a powershell session and mount your vhd (using the gui or diskpart), them run a 'test-path I:\' (or whatever comes up as your drive letter) it comes back as "true" (which is what you want). I dismount the disk and run 'test-path I:\' again and get "false". Still good feedback. I mount the disk again (or another disk) and run 'test-path I:\' again it comes back as "false" (should be "true") and you can't navigate to the drive letter within the powershell instance. If I open up a new session I can navigate to I: fine.

Kyle
  • 121
  • 4
  • possible duplicate of [Using Diskpart in a PowerShell script won't allow script to reuse drive letter](http://serverfault.com/questions/456908/using-diskpart-in-a-powershell-script-wont-allow-script-to-reuse-drive-letter) – Mathias R. Jessen Dec 19 '12 at 20:36

1 Answers1

1

There are multiple things in play here. The most important being that Powershell does not run in the same context as your Windows Explorer - so it doesn't know about drives attached there, and vice-versa.

Secondly, get rid of diskpart and use Powershell's own facilities. Have a look at "New-PSDrive" (http://technet.microsoft.com/en-us/library/hh849829.aspx) for a start.

Thirdly, it's possible that these operations are asynchronous, and you may have your script wait a bit until the drive letter is removed/attached. (Doesn't happen manually because you're slow enough compared to the script execution).

Roman
  • 3,825
  • 3
  • 20
  • 33
  • new-PSdrive doesn't allow you to mount a VHD (or atleast I haven't found a way). What I have found is that the problem I described above stems from using Test-path. Don't believe me, try this: – Kyle Feb 13 '14 at 15:13