Set Harddrive On/Offline

I am trying to replicate a manual process I am doing in the disk management section of a server I am working with.  The server is Windows 2008 R2 Standard.
1. I go into the Disk Management Section
2. Right click on a basic drive and select "Offline"
3. Change out my harddrive
4. Right click on the same basic drive and select "Online"

How can I replicate this process in VB.NET code?  Is it possible?
jdonagheAsked:
Who is Participating?
 
nffvrxqgrcfqvvcConnect With a Mentor Commented:
There isn't much documentation but if the (online) (offline) feature works like most disks chances are you would want to lock the volume first. This prevents reads/writes in progress from being corrupted. If that check is OK it's safe to dismount and then turn the volume offline.
Usage:

Public Class Form1
Dim disk As New VolumeHelper("e:")
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
disk.SafeOffline()
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
disk.Online()
disk.Close()
End Sub
End Class

Imports System.Runtime.InteropServices
Imports System.Security.Permissions
Imports Microsoft.Win32.SafeHandles
Imports System.Runtime.ConstrainedExecution

Public Class VolumeHelper
' Safe Offline/Online
' egl1044
    Private Const GENERIC_READ As Integer = &H80000000
    Private Const GENERIC_WRITE As Integer = &H40000000
    Private Const FILE_SHARE_READ As Integer = &H1
    Private Const FILE_SHARE_WRITE As Integer = &H2
    Private Const OPEN_EXISTING As Integer = 3
    Private Const ERROR_NOT_READY As Integer = 21

    Private Const IOCTL_VOLUME_ONLINE As Integer = &H56C008
    Private Const IOCTL_VOLUME_OFFLINE As Integer = &H56C00C
    Private Const FSCTL_LOCK_VOLUME As Integer = &H90018
    Private Const FSCTL_UNLOCK_VOLUME As Integer = &H9001C
    Private Const FSCTL_DISMOUNT_VOLUME As Integer = &H90020

    <DllImport("kernel32.dll", CharSet:=CharSet.Auto, ExactSpelling:=True, SetLastError:=True)> _
    Private Shared Function DeviceIoControl(ByVal hDevice As SafeVolumeHandle, ByVal dwIoControlCode As Integer, ByVal lpInBuffer As IntPtr, ByVal nInBufferSize As Integer, ByVal lpOutBuffer As IntPtr, ByVal nOutBufferSize As Integer, ByRef lpBytesReturned As Integer, ByVal lpOverlapped As IntPtr) As Integer
    End Function
    <DllImport("kernel32.dll", CharSet:=CharSet.Unicode, SetLastError:=True)> _
    Private Shared Function CreateFile(ByVal lpFileName As String, ByVal dwDesiredAccess As Integer, ByVal dwShareMode As Integer, ByVal lpSecurityAttributes As IntPtr, ByVal dwCreationDisposition As Integer, ByVal dwFlagsAndAttributes As Integer, ByVal hTemplateFile As IntPtr) As SafeVolumeHandle
    End Function

    Private VolumeHandle As SafeVolumeHandle = Nothing
    Private lpBytesReturned As Integer = 0

    Public Sub New(ByVal drive As String)
        InitializeVolumeHandle(drive)
    End Sub
    Protected Overrides Sub Finalize()
        If Not IsNothing(VolumeHandle) Then
            VolumeHandle.Dispose()
        End If
        MyBase.Finalize()
    End Sub
    Private Sub InitializeVolumeHandle(ByVal drive As String)
        Dim tmpVolumeHandle As SafeVolumeHandle
        tmpVolumeHandle = CreateFile("\\.\" & drive, GENERIC_READ Or GENERIC_WRITE, _
                                     FILE_SHARE_READ Or FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero)
        If Not tmpVolumeHandle.IsInvalid Then
            VolumeHandle = tmpVolumeHandle
        Else
            Console.WriteLine("Invalid Volume Handle")
            Console.WriteLine(Marshal.GetLastWin32Error)
        End If
    End Sub
    Public Sub Online()
        If Not IsNothing(VolumeHandle) Then
            If DeviceIoControl(VolumeHandle, IOCTL_VOLUME_ONLINE, _
                               IntPtr.Zero, 0, IntPtr.Zero, 0, lpBytesReturned, IntPtr.Zero) Then
                Console.WriteLine("Online")
            Else
                Console.WriteLine(Marshal.GetLastWin32Error)
            End If
        End If
    End Sub
    Public Sub SafeOffline()
        If Not IsNothing(VolumeHandle) Then
            ' Attempt to lock the volume.
            If DeviceIoControl(VolumeHandle, FSCTL_LOCK_VOLUME, _
                               IntPtr.Zero, 0, IntPtr.Zero, 0, lpBytesReturned, IntPtr.Zero) Then

                Console.WriteLine("Locking volume...")

                ' DISMOUNT the volume and flush cache and any associations on the systems.
                If DeviceIoControl(VolumeHandle, FSCTL_DISMOUNT_VOLUME, _
                                   IntPtr.Zero, 0, IntPtr.Zero, 0, lpBytesReturned, IntPtr.Zero) Then

                    Console.WriteLine("Dismounting volume...")

                    If DeviceIoControl(VolumeHandle, IOCTL_VOLUME_OFFLINE, _
                             IntPtr.Zero, 0, IntPtr.Zero, 0, lpBytesReturned, IntPtr.Zero) Then

                        Console.WriteLine("Volume Offline.")
                    Else
                        Console.WriteLine("IOCTL_VOLUME_OFFLINE error {0}", Marshal.GetLastWin32Error)
                    End If
                Else
                    Console.WriteLine("FSCTL_DISMOUNT_VOLUME error {0}", Marshal.GetLastWin32Error)
                End If
            Else
                Console.WriteLine("The volume has open files or read/write in progress the operation has been aborted to prevent data loss. FSCTL_LOCK_VOLUME {0}", Marshal.GetLastWin32Error)
            End If
        End If
    End Sub

    Public Sub Close()
        If Not IsNothing(VolumeHandle) Then
            VolumeHandle.Close()
        End If
    End Sub

End Class

<SecurityPermission(SecurityAction.InheritanceDemand, UnmanagedCode:=True)> _
<SecurityPermission(SecurityAction.Demand, UnmanagedCode:=True)> _
Public Class SafeVolumeHandle
    Inherits SafeHandleZeroOrMinusOneIsInvalid
    <DllImport("kernel32.dll", CharSet:=CharSet.Auto, ExactSpelling:=True, SetLastError:=True)> _
    <ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)> _
    Private Shared Function CloseHandle(ByVal lpObject As IntPtr) As Integer
    End Function
    Private Sub New()
        MyBase.New(True)
    End Sub
    <ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)> _
    Protected Overloads Overrides Function ReleaseHandle() As Boolean
        Return CloseHandle(handle)
    End Function
End Class

Open in new window

0
 
Shahan AyyubConnect With a Mentor Senior Software Engineer - iOSCommented:
Can you try this link:

http://www.codeproject.com/KB/cs/HardwareHelper.aspx

Download this project.

Well this is in C# not in VB.NET but will help you,It enables and disables the device mentioned in the list.


-Shahan
0
 
jdonagheAuthor Commented:
Actually this partially solves my problem.  I was going to ask about Server 2003 after I got the 2008 problem solved.  This solution helps with 2003 because it disables the drive like I would in the device manager.  But when I checked the device manager in 2008, if I took the drive offline in the disk management it still showed being active in the device manager.
0
 
jdonagheAuthor Commented:
Although both these solutions did not replicate the exact steps I would take on the 2008 server, both solutions worked fine.  The only thing I found out was when I am ready to enable the drive again I had to wait 30 seconds to a minute to let the hardware recognize there was a drive there, then I would enable it.  Thanks for your help.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.