DiskManagement.psm1

function Edit-Disk {
        <#
        .SYNOPSIS
        This Cmdlet will avoid the manual setup of a disk which was attached via Tic to a target.
        requirements:
            - Windows 8.1 / Windows 2012R2 (NT 6.3) or newer
            - Administrator privileges
        author:
            - Marc Tschapek (c5211773)
        license:
            - Copyright: (c) 2017, Marc Tschapek <marc.tschapek@itelligence.de>
            - BSD-2-Clause (see https://opensource.org/licenses/BSD-2-Clause)
        .DESCRIPTION
           - Select and manage a disk, its partitions and file systems
           - The alias for Edit-Disk which you can also use is Manage-Disk

        DYNAMIC PARAMETERS
        - SetDriveLetter
                - Manage disk parameter.
                - Drive letter which will be set for the partition on selected disk.
                - This dynamic parameter let's you browse through all available drive letters
                  on the target directly (with Tab key) if you set -SetDriveLetter while invoking the Cmdlet.
                - If you pass a drive letter to the Cmdlet which was chosen by your own (without Tab key to get
                  the free drive letters automatically) the Cmdlet will use this drive letter if it is a free drive
                  letter on the target. If the passed drive letter is not a free drive letter on the target,
                  the Cmdlet will be canceled.
                - If no SetDriveLetter parameter value was passed but a valid value for parameter SetPartitionAccessPath
                  was passed to the Cmdlet, the Cmdlet will create this partition access path
                  and no drive letter for the partition on selected disk.
                - If no SetDriveLetter parameter value and no value for parameter SetPartitionAccessPath
                  was passed to the Cmdlet, the Cmdlet will set a free drive letter for the partition randomly
                  and no partition access path on selected disk. If in this case no free drive lettter is left on the target
                  the Cmdlet will be canceled.
                - If a valid value for SetDriveLetter and for SetPartitionAccessPath parameter was passed to the Cmdlet,
                  the Cmdlet will setup this partition drive letter and access path on selected disk.
        - SetLargerFRS
                - Manage disk parameter.
                - Switch to set Large FRS parameter for file system on selected disk, solely settable for ntfs file system.
                - This switch depends on the SetFileSystem parameter and can only passed to the Cmdlet
                  if SetFileSystem parameter has value "ntfs".
        - SetShortNames
                - Manage disk parameter.
                - Switch to set Short Names parameter for file system on selected disk, solely settable for ntfs file system.
                - This switch depends on the SetFileSystem parameter and can only passed to the Cmdlet
                  if SetFileSystem parameter has value "ntfs".
        - SetIntegrityStreams
                - Manage disk parameter.
                - Switch to set Integrity Streams parameter for file system on selected disk, solely settable
                  for refs file system.
                - This switch depends on the SetFileSystem parameter and can only passed to the Cmdlet
                  if SetFileSystem parameter has value "refs".
        .PARAMETER GetSize
        - Select disk parameter.
        - Size of the disk in gigabyte which will be selected.
        - If a size is passed the Cmdlet will try to select the disk with this size.
        - GetSize value must be equal or greater than 1gb and maximum 18446744073709551615gb.
        .PARAMETER GetPartitionStyle
        - Select disk parameter.
        - Partition style of the disk which will be selected.
        .PARAMETER GetOperationalStatus
        - Select disk parameter.
        - Operational Status of the disk which will be selected.
        .PARAMETER IsNotReadOnly
        - Select disk parameter.
        - Default behavior of the Cmdlet is, that the disk which will be selected
          has to be in read-only status.
        - With this switch you can specify that the disk which will be selected
          is not in read-only status (disk is writeable).
        .PARAMETER GetNumber
        - Select disk parameter.
        - Number of the disk which will be selected.
        - If a number is passed the Cmdlet will try to select the disk with this number.
        - Passed value will be checked in the beginning of the Cmdlet whether it is an int32 value.
        - If it is of type in64 the Cmdlet will be canceled.
        .PARAMETER SetPartitionStyle
        - Manage disk parameter.
        - Partition style which will be set on selected disk.
        .PARAMETER SetPartitionAccessPath
        - Manage disk parameter.
        - Access path which will be set on partition of selected disk.
        - The Cmdlet validates whether the passed value is already in use as access path by another disk,
          is a proper path/directory/folder on the target, is already in use as a link
          and whether it is empty (no files or folders inside).
        - This parameter has some dependencies with the dynamic parameter SetDriveLetter.
          For more information read the DYNAMIC PARAMETERS part of the help section.
        .PARAMETER SetFileSystem
        - Manage disk parameter.
        - File system which will be set on selected disk.
        - Maximum volume size for ntfs is 256000gb.
        - Maximum volume size for refs is the maximum GetSize parameter value 18446744073709551615gb.
        - If the disk size of the selected disk does not match with the passed value
          for parameter SetFileSystem (e.g. "ntfs" over 256000gb) the Cmdlet will be canceled.
        - Also consider the dynamic parameters SetLargerFRS, SetShortNames and SetIntegrityStreams
          which are switches who can be set in addition to the FileSystem parameter
          but they depend on the passed file system value. For more information read the DYNAMIC PARAMETERS
          part of the help section.
        .PARAMETER SetLabel
        - Manage disk parameter.
        - File system label which should be set for the file system on selected disk.
        .PARAMETER SetAllocationUnitSize
        - Manage disk parameter.
        - Allocation unit size which will be set for the file system on selected disk
          (possible values for file system ntfs 4,8,16,32,64kb;refs 64kb).
        - If parameter SetFileSystem is set to "refs" the allocation unit size will be automatically adjusted to "64" (kb).
        .EXAMPLE
        Manage-Disk -GetNumber 1 -GetPartitionStyle 'raw' -GetOperationalStatus 'offline' `
        -SetPartitionStyle 'mbr' -SetPartitionAccessPath C:\Test -SetFileSystem 'ntfs' -SetLabel 'database_disk' -SetLargeFRS -SetShortNames -WhatIf
 
        This example would try to select and set the disk as specified and shows verbose logging information
        but would not apply any changes to the target because of the passed common parameter WhatIf.
        .EXAMPLE
        powershell -command "Edit-Disk -GetSize 50 -GetPartitionStyle 'mbr' -GetOperationalStatus 'online' -IsNotReadOnly `
        -SetPartitionStyle 'gpt' -SetDriveLetter F -SetFileSystem 'refs' -SetLabel 'application_disk' -SetAllocationUnitSize 64 -SetIntegrityStreams -Verbose"
 
        This example would try to select and set the disk as specified.
        Furthermore it will show what was changed on the target caused by the common parameter -Verbose.
        In this example the Cmdlet is started in a new PowerShell session.
        This is useful if you want to invoke the Cmdlet from within cmd or another tool which is not a PowerShell host (for instance Oasis).
        .INPUTS
        None. You cannot pipe objects to Edit-Disk.
        .OUTPUTS
        System.String. Edit-Disk returns a string with a in JSON converted hashtable.
        The hashtable contains the following items and sub-items:
 
        - changed
            - Whether anything was changed.
            Returned: always
            Type: boolean
            Sample: true

        - message
            - Possible error message on failure.
            Returned: failed
            Type: string
            Sample: "No free drive letter left on the target"

        - change_log
            - Dictionary containing all the detailed information about changes on the selected disk.
            Returned: if -WhatIf or/and -Verbose option was passed to the Cmdlet
            Type: complex
            Contains:

                operational_status
                    - Detailed information about setting operational status of the disk.
                    Returned: success or failed
                    Type: string
                    Sample: "Disk set online"

                writeable_status
                    - Detailed information whether disk was set from read-only to writeable.
                      and if not why it was not set to it.
                    Returned: success or failed
                    Type: string
                    Sample: "Disk set from read-only to writeable"

                allocation_unit
                    - Information whether allocation_unit_size value was automatically adjusted.
                    Returned: if file_system option value was refs and allocation_unit_size value was not 64
                    Type: string
                    Sample: "Size was automatically adjusted to 64kb due to file_system option value refs"

                initializing
                    - Detailed information about initializing the disk.
                    Returned: success or failed
                    Type: string
                    Sample: "Disk initialization successful - Partition style raw (GetPartitionStyle)
                    was initalized to gpt (SetPartitionStyle)"

                converting
                    - Detailed information about converting the partition style.
                      of the disk (in case of converting no initalization of disk).
                    Returned: success or failed
                    Type: string
                    Sample: "Partition style mbr (GetPartitionStyle) was converted
                    to gpt (SetPartitionStyle)"

                partitioning
                    - Detailed information about partition creation on the selected disk.
                    Returned: success or failed
                    Type: string
                    Sample: "Initial partition Basic was created successfully on partition style gpt"

                access_path
                    - Detailed information about access path creation on the partition of selected disk.
                    Returned: success or failed
                    Type: string
                    Sample: "Partition access path C:\\Test was created successfully for partition Basic"

                formatting
                    - Detailed information about volume creation on partitoned disk.
                    Returned: success or failed
                    Type: string
                    Sample: "Volume ReFS was created successfully on partition Basic"

                shellhw_service_state
                    - Detailed information about executed ShellHWService action (start, stop).
                    Returned: success or failed
                    Type: string
                    Sample: "Could not be set from 'Stopped' to 'Running' again"
        .NOTES
          - To select the disk and to manage it you have several parameters which are all described in the documentation.
          - If you invoke the Cmdlet without any parameter the default parameter values will be used.
          - If you pass a decimal value for any of the int parameters it will be rounded to an even number.
          - To identify the parameters which are used to select a disk consider the "Get" verb in front of the parameter
            (except for -IsNotReadOnly which is also a a select parameter) and the "Select disk parameter" hint in the parameter description.
          - To identify the parameters which are used to manage a disk consider the "Set" verb in front of the parameter and the
            "Manage disk parameter" hint in the parameter description.
          - In order to find only one disk on the target you can use the GetSize and/or GetNumber parameter for the search of the disk.
          - If no GetSize and GetNumber parameter value was defined and multiple disks were found on the target based on the passed parameter values
            the Cmdlet will select the first disk found.
          - There is one known bug if you don't set any value for parameter SetFileSystem. The dynamic variables get somehow
          - The Cmdlet detects any existing volume and/or partition on the selected disk and will cancel the Cmdlet in this case.
          - If the disk is not yet initialized the Cmdlet will initialize the disk (set partition style, online and writeable).
          - If the disk is initialized already the Cmdlet will try to set the disk to "online" and "writeable" (read-only eq. false)
            if it's not the state of the disk already.
          - Further in this case it will convert the partition style of the disk to the selected partition style if needed.
          - The Cmdlet will stop and start the service "ShellHWService" again in order to avoid disk management GUI messages.
          - If the Cmdlet fails with an error and the operational status was set from "offline" to "online" before the Cmdlet will try to set
            the disk to operational status "offline" again but will not be canceled if set "offline" again fails.
          - If the Cmdlet fails with an error and the writeable status was set from "read-only" to "writeable" before the Cmdlet will try to set
            the disk to writeable status "read-only" again but will not be canceled if set "read-only" again fails.
          - If you use the common parameter -Verbose you will get detailed information about the changes on the target.
          - If you use the common parameter -WhatIf nothing will be changed on the target but you will get the information
            what would be changed (contains -Verbose).
          - If you invoke the Cmdlet all common parameters are available but only -Verbose, -Whatif and -Confirm will take an affect.
          - Please note that in this Cmdlet -Verbose and -WhatIf does act in a different way as usual
            because of the hashtable output (manual created Verbose and WhatIf output, not the standard Cmdlets output).
          - The Confirm parameter acts as per PowerShell standard behavior.
          - Of course you can use the common parameter -OutVariable.
          - The Cmdlet needs to be invoked with administrator privileges otherwise the Cmdlet will be canceled.
        .LINK
        Ansible Version: https://github.com/ansible/ansible/pull/27634
        .LINK
        Get-Disk
        Get-Volume
        Set-Disk
        Initialize-Disk
        New-Partition
        Format-Volume
        #>

        [CmdletBinding(
            SupportsShouldProcess = $true,
            ConfirmImpact = "High"
            )
        ]
        param(
                [Parameter(Position = 0)]
                [ValidateRange(1,18446744073709551615)]
                [uint64]$GetSize,
                [Parameter(Position = 1)]
                [ValidateNotNullorEmpty()]
                [int32]$GetNumber,
                [Parameter(Position = 2)]
                [ValidateSet("raw", "mbr", "gpt")]
                [string]$GetPartitionStyle = "raw",
                [Parameter(Position = 3)]
                [ValidateSet("offline", "online")]
                [string]$GetOperationalStatus = "offline",
                [Parameter(Position = 4)]
                [switch]$IsNotReadOnly,
                [Parameter(
                    Position = 5,
                    Mandatory = $true,
                    HelpMessage = "Please enter a valid partition style (gpt or mbr) which should be set on the selected disk"
                    )
                ]
                [ValidateSet("gpt", "mbr")]
                [string]$SetPartitionStyle,
                [Parameter(Position = 7)]
                [ValidateScript( {
                            if ((-not ((Get-Partition).AccessPaths -like "$_*")) -and (Test-Path $_ -PathType Container) -and ((Get-Item $_).LinkType -eq $null)) {
                                if (-not (Get-ChildItem $_)) {
                                    $true
                                } else {
                                    throw "$_ is not an empty folder (contains files and/or folders)"                                    
                                }
                            } elseif ((Get-Partition).AccessPaths -like "$_*") {
                                throw "$_ is already in use as access path by another disk"
                            } elseif (-not (Test-Path $_ -PathType Container)) {
                                throw "$_ is not a valid path/directory/folder on the target for parameter SetPartitionStyle"
                            } elseif((Get-Item $_).LinkType -ne $null) {
                                throw "$_ is already in use as a link of type $((Get-Item $_).LinkType)"
                            }
                        }
                    )
                ]
                [string]$SetPartitionAccessPath,
                [Parameter(
                    Position = 8,
                    Mandatory = $true,
                    HelpMessage = "Please enter a valid file system (ntfs or refs) which should be set on the selected disk"
                    )
                ]
                [ValidateNotNullorEmpty()]
                [ValidateSet("ntfs", "refs")]
                [string]$SetFileSystem,
                [Parameter(Position = 9)]
                [ValidateNotNullorEmpty()]
                [string]$SetLabel = "additional_disk",
                [Parameter(
                    Position = 10,
                    Mandatory = $true,
                    HelpMessage = "Please enter a valid allocation unit size (4, 8, 16, 32 or 64) which should be set for the file system on the selected disk"
                    )
                ]
                [ValidateSet(4,8,16,32,64)]
                [int32]$SetAllocationUnitSize
        )
        DynamicParam {
                $DriveLetterAttribute = New-Object System.Management.Automation.ParameterAttribute
                $DriveLetterAttribute.Position = 6
                $DriveLetterAttribute.ParameterSetName = '__AllParameterSets'
                $attributeCollectionDriveLetter = New-Object System.Collections.ObjectModel.Collection[System.Attribute]
                $attributeCollectionDriveLetter.Add($DriveLetterAttribute)
                $Letters  = try {
                                        (Get-ChildItem Function:[a-z]: -Name | Where-Object {
                                            -not (Test-Path -Path $_)
                                        }).TrimEnd(":")
                                    } catch {
                                        throw "Gather all free drive letters on the target failed"
                                    }
                $attributeCollectionDriveLetter.Add((New-Object  System.Management.Automation.ValidateSetAttribute($Letters)))  
                $DriveLetterParam = New-Object System.Management.Automation.RuntimeDefinedParameter('SetDriveLetter', [char], $attributeCollectionDriveLetter)
                $paramDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
                $paramDictionary.Add('SetDriveLetter', $DriveLetterParam)
            
            if ($PSBoundParameters["SetFileSystem"]) {
                if ($SetFileSystem -eq "ntfs") {
                    $LargeFRSAttribute = New-Object System.Management.Automation.ParameterAttribute
                    $LargeFRSAttribute.Position = 11
                    $LargeFRSAttribute.ParameterSetName = '__AllParameterSets'
                    $attributeCollectionFRS = New-Object System.Collections.ObjectModel.Collection[System.Attribute]
                    $attributeCollectionFRS.Add($LargeFRSAttribute)         
                    $LargeFRSParam = New-Object System.Management.Automation.RuntimeDefinedParameter('SetLargeFRS', [switch], $attributeCollectionFRS)

                    $paramDictionary.Add('SetLargeFRS', $LargeFRSParam)
                
                    $ShortNamesAttribute = New-Object System.Management.Automation.ParameterAttribute
                    $ShortNamesAttribute.Position = 12
                    $ShortNamesAttribute.ParameterSetName = '__AllParameterSets'
                    $attributeCollectionShort = New-Object System.Collections.ObjectModel.Collection[System.Attribute]
                    $attributeCollectionShort.Add($ShortNamesAttribute)
                    $ShortNamesParam = New-Object System.Management.Automation.RuntimeDefinedParameter('SetShortNames', [switch], $attributeCollectionShort)
                    $paramDictionary.Add('SetShortNames', $ShortNamesParam)

                } elseif ($SetFileSystem -eq "refs") {
                    $IntegrityStreamsAttribute = New-Object System.Management.Automation.ParameterAttribute
                    $IntegrityStreamsAttribute.Position = 13
                    $IntegrityStreamsAttribute.ParameterSetName = '__AllParameterSets'
                    $attributeCollection = New-Object System.Collections.ObjectModel.Collection[System.Attribute]
                    $attributeCollection.Add($IntegrityStreamsAttribute)
                    $IntegrityStreamsParam = New-Object System.Management.Automation.RuntimeDefinedParameter('SetIntegrityStreams', [switch], $attributeCollection)

                    $paramDictionary.Add('SetIntegrityStreams', $IntegrityStreamsParam)
                }
            }
        return $paramDictionary
        }

        Process {
            # Check WhatIf and Verbose parameter
            [bool]$CheckMode = $WhatIfPreference
            [bool]$Verbose = if ($PSBoundParameters["Verbose"]) {
                                        $true
                                    } else {
                                        $false
                                    }

            # Create a new result object
            [hashtable]$result = @{
                    message = [string]::Empty
                    failed = $false
                    changed = $false
            }

            # Functions
            function Test-Admin {
                    $CurrentUser = New-Object Security.Principal.WindowsPrincipal $([Security.Principal.WindowsIdentity]::GetCurrent())
                    $IsAdmin = $CurrentUser.IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator)

                    return $IsAdmin
            }

            function Search-Disk {
                    param(
                            $DiskSize,
                            $PartitionStyle,
                            $OperationalStatus,
                            $ReadOnly,
                            $Number
                    )
                    if ($DiskSize -ne $null) {
                        $DiskSize = $DiskSize *1GB
                    }
                    if ($DiskSize -and ($Number -ne $null)) {
                        $disk = Get-Disk | Where-Object {
                            ($_.PartitionStyle -eq $PartitionStyle) -and ($_.OperationalStatus -eq $OperationalStatus) -and ($_.IsReadOnly -eq $ReadOnly) -and ($_.Size -eq $DiskSize) -and ($_.Number -eq $Number)
                        }
                    } elseif ($DiskSize) {
                        $disk = Get-Disk | Where-Object {
                            ($_.PartitionStyle -eq $PartitionStyle) -and ($_.OperationalStatus -eq $OperationalStatus) -and ($_.IsReadOnly -eq $ReadOnly) -and ($_.Size -eq $DiskSize)
                        }
                    } elseif ($Number -ne $null) {
                        $disk = Get-Disk | Where-Object {
                            ($_.PartitionStyle -eq $PartitionStyle) -and ($_.OperationalStatus -eq $OperationalStatus) -and ($_.IsReadOnly -eq $ReadOnly) -and ($_.Number -eq $Number)
                        }
                    } else {
                        $disk = Get-Disk | Where-Object {
                            ($_.PartitionStyle -eq $PartitionStyle) -and ($_.OperationalStatus -eq $OperationalStatus) -and ($_.IsReadOnly -eq $ReadOnly)
                        }
                    }

                    return $disk
            }

            function Set-OperationalStatus {
                    param(
                            $Disk,
                            [switch]$Deactivate
                    )
                    $null = Set-Disk -Number ($Disk.Number) -IsOffline $Deactivate.IsPresent
            }

            function Set-DiskWriteable {
                    param(
                            $Disk,
                            [switch]$Deactivate
                    )
                    $null = Set-Disk -Number ($Disk.Number) -IsReadonly $Deactivate.IsPresent
            }

            function Search-Volume {
                    param(
                            $Partition
                    )
                    $FoundVolume = Get-Volume | Where-Object {
                        $Partition.AccessPaths -like $_.ObjectId
                    }
                    if ($FoundVolume -eq $null) {
            
                        return $false
                    }

                    return $FoundVolume
            }

            function Set-Initialized {
                    param(
                            $Disk,
                            $PartitionStyle
                    )
                    $null = $Disk| Initialize-Disk -PartitionStyle $PartitionStyle -Confirm:$false
            }

            function Convert-PartitionStyle {
                    param(
                            $Disk,
                            $PartitionStyle
                    )
                    $null = Invoke-Expression "'Select Disk $($Disk.Number)','Convert $($PartitionStyle)' | diskpart"
            }

            function Manage-ShellHWService {
                    param(
                            $Action
                    )
                    switch ($Action) {
                            Stop {
                                $null = Stop-Service -Name ShellHWDetection
                            }
                            Start {
                                $null = Start-Service -Name ShellHWDetection
                            }
                            Check {
                                $CheckService = (Get-Service ShellHWDetection).Status -eq "Running"

                                return $CheckService
                            }
                    }
            }

            function Create-Partition {
                    param(
                            $Disk,
                            $SetDriveLetter
                    )
                    if (-not $SetDriveLetter -eq [string]::Empty) {
                        $Partition = $Disk | New-Partition -UseMaximumSize -DriveLetter $SetDriveLetter
                    } else {
                        $Partition = $Disk | New-Partition -UseMaximumSize
                    }

                    return $Partition
            }

            function Add-AccessPath {
                    param(
                            $Partition,
                            $Path
                    )
                    $null = $Partition | Add-PartitionAccessPath -AccessPath $Path
            }

            function Create-Volume {
                    param(
                            $Volume,
                            $FileSystem,
                            $FileSystemLabel,
                            $FileSystemAllocUnitSize,
                            $FileSystemLargeFRS,
                            $FileSystemShortNames,
                            $FileSystemIntegrityStreams
                    )
                    $Alloc = $FileSystemAllocUnitSize *1KB
                    [hashtable]$ParaVol = @{
                        FileSystem = $FileSystem
                        NewFileSystemLabel = $FileSystemLabel
                        AllocationUnitSize = $Alloc
                    }
                    switch ($FileSystem) {
                            ntfs {
                                $ParaVol += @{ShortFileNameSupport = $FileSystemShortNames; UseLargeFRS = $FileSystemLargeFRS}
                            }
                            refs {
                                $ParaVol['SetIntegrityStreams'] = $FileSystemIntegrityStreams
                            }
                    }
                    $CreatedVolume = $Volume | Format-Volume @ParaVol -Force -Confirm:$false

                    return $CreatedVolume
            }

            # Check admin rights
            if (-not (Test-Admin)) {
                $result.message = "Cmdlet was not started with elevated rights"
                $result.failed = "true"
                return $result | ConvertTo-Json
            }

            # Rescan disks
            $null = Invoke-Expression '"rescan" | diskpart'

            # Search disk
            [hashtable]$ParamsDisk = @{
                DiskSize = if ($PSBoundParameters["GetSize"]) {
                                        $GetSize
                                    } else {
                                        $null
                                    }
                PartitionStyle = $GetPartitionStyle
                OperationalStatus = $GetOperationalStatus
                ReadOnly = if ($IsNotReadOnly.IsPresent) {
                                          $false
                                      } else {
                                          $true
                                      }
                Number = if ($PSBoundParameters["GetNumber"]) {
                                        $GetNumber
                                    } else {
                                        $null
                                    }
            }
            try {
                $disk = Search-Disk @ParamsDisk
            } catch {
                $result.message = "Failed to search and/or select the disk with the specified parameter values: $($_.Exception.Message)"
                $result.failed = "true"
                return $result | ConvertTo-Json
            }
            if ($disk) {
                $diskcount = $disk | Measure-Object | Select-Object  -ExpandProperty Count
                if ($diskcount -ge 2) {
                    $disk = $disk[0]
                }
                [string]$DOperSt = $disk.OperationalStatus
                [string]$DPartStyle = $disk.PartitionStyle
                [string]$DROState = $disk.IsReadOnly
            } else {
                    $result.message = "No disk could be found and selected with the passed parameter values"
                    $result.failed = "true"
                    return $result | ConvertTo-Json
            }
        
            # Create change log
            if ($CheckMode -or $Verbose) {
                $result += @{ 
                    change_log = @{
                    }
                }
            }

            # Check and set operational status and read-only state
            $SetOnline = $false
            $SetWriteable = $false
            $OPStatusFailed = $false
            $ROStatusFailed = $false
            if ($DPartStyle -ne "RAW") {
                if ($DOperSt -ne "Online") {
                    if (-not $CheckMode) {
                        # Set online
                        try {
                            Set-OperationalStatus -Disk $disk
                        } catch {
                            $result.message = "Failed to set the disk online: $($_.Exception.Message)"
                            $result.failed = "true"
                            if ($Verbose) {
                                $result.Remove("change_log")
                            }
                            return $result | ConvertTo-Json
                        }
                        if ($Verbose) {
                            $result.change_log.operational_status = "Disk set online"
                        }
                        $result.changed = $true
                        $SetOnline = $true
                    } else {
                        $result.change_log.operational_status = "Disk is offline but was not set online due to passed -WhatIf switch"
                    }
                }      
                if ($DROState -eq "True") {
                    if (-not $CheckMode) {
                        # Set writeable
                        try {
                            Set-DiskWriteable -Disk $disk
                        } catch {
                            if ($Verbose) {
                                $result.change_log.writeable_status = "Disk failed to set from read-only to writeable"
                            }
                            if ($SetOnline) {
                                try {
                                    Set-OperationalStatus -Disk $disk -Deactivate
                                } catch {
                                    $OPStatusFailed = $true
                                } finally {
                                    if (-not $OPStatusFailed) {
                                        if ($Verbose) {
                                            $result.change_log.operational_status = "Disk set online and now offline again"
                                        }
                                        $result.changed = $true
                                    } else {
                                        if ($Verbose) {
                                            $result.change_log.operational_status = "Disk failed to set offline again"
                                        }
                                    }
                                }
                            }
                            $result.message = "Failed to set the disk from read-only to writeable state: $($_.Exception.Message)"
                            $result.failed = "true"
                            return $result | ConvertTo-Json
                        }
                        if ($Verbose) {
                            $result.change_log.writeable_status = "Disk set from read-only to writeable"
                        }
                        $result.changed = $true
                        $SetWriteable = $true
                    } else {
                        $result.change_log.writeable_status = "Disk is read-only but was not set writeable due to passed -WhatIf switch"
                    }
                } 
            }

            # Check volumes and partitions
            [string]$PartNumber = $disk.NumberOfPartitions
            # Verify partitons and volumes
            if ($PartNumber -ge 1) {
                # Collect partitions
                try {
                    $partition = Get-Partition -DiskNumber $disk.Number
                } catch {
                    if ($SetOnline) {
                        try {
                            Set-OperationalStatus -Disk $disk -Deactivate
                        } catch {
                            $OPStatusFailed = $true
                        } finally {
                            if (-not $OPStatusFailed) {
                                if ($Verbose) {
                                    $result.change_log.operational_status = "Disk set online and now offline again"
                                }
                                $result.changed = $true
                            } else {
                                if ($Verbose) {
                                    $result.change_log.operational_status = "Disk failed to set offline again"
                                }
                            }
                        }
                    }
                    if ($SetWriteable) {
                        try {
                            Set-DiskWriteable -Disk $disk -Deactivate
                        } catch {
                            $ROStatusFailed = $true
                        } finally {
                            if (-not $ROStatusFailed) {
                                if ($Verbose) {
                                    $result.change_log.writeable_status = "Disk set writeable and now read-only again"
                                }
                                $result.changed = $true
                            } else {
                                if ($Verbose) {
                                    $result.change_log.writeable_status = "Disk failed to set read-only again"
                                }
                            }
                        }
                    }
                    $result.message = "General error while searching for partitions on the selected disk: $($_.Exception.Message)"
                    $result.failed = "true"
                    return $result | ConvertTo-Json
                }
                # Collect volumes
                try {
                    $volume = Search-Volume -Partition $partition
                } catch {
                    if ($SetOnline) {
                        try {
                            Set-OperationalStatus -Disk $disk -Deactivate
                        } catch {
                            $OPStatusFailed = $true
                        } finally {
                            if (-not $OPStatusFailed) {
                                if ($Verbose) {
                                    $result.change_log.operational_status = "Disk set online and now offline again"
                                }
                                $result.changed = $true
                            } else {
                                if ($Verbose) {
                                    $result.change_log.operational_status = "Disk failed to set offline again"
                                }
                            }
                        }
                    }
                    if ($SetWriteable) {
                        try {
                            Set-DiskWriteable -Disk $disk -Deactivate
                        } catch {
                            $ROStatusFailed = $true
                        } finally {
                            if (-not $ROStatusFailed) {
                                if ($Verbose) {
                                    $result.change_log.writeable_status = "Disk set writeable and now read-only again"
                                }
                                $result.changed = $true
                            } else {
                                if ($Verbose) {
                                    $result.change_log.writeable_status = "Disk failed to set read-only again"
                                }
                            }
                        }
                    }
                    $result.message = "General error while searching for volumes on the selected disk: $($_.Exception.Message)"
                    $result.failed = "true"
                    return $result | ConvertTo-Json
                }
                # Existent volumes and partitions
                if (-not $volume) {
                    if ($SetOnline) {
                        try {
                            Set-OperationalStatus -Disk $disk -Deactivate
                        } catch {
                            $OPStatusFailed = $true
                        } finally {
                            if (-not $OPStatusFailed) {
                                if ($Verbose) {
                                    $result.change_log.operational_status = "Disk set online and now offline again"
                                }
                                $result.changed = $true
                            } else {
                                if ($Verbose) {
                                    $result.change_log.operational_status = "Disk failed to set offline again"
                                }
                            }
                        }
                    }
                    if ($SetWriteable) {
                        try {
                            Set-DiskWriteable -Disk $disk -Deactivate
                        } catch {
                            $ROStatusFailed = $true
                        } finally {
                            if (-not $ROStatusFailed) {
                                if ($Verbose) {
                                    $result.change_log.writeable_status = "Disk set writeable and now read-only again"
                                }
                                $result.changed = $true
                            } else {
                                if ($Verbose) {
                                    $result.change_log.writeable_status = "Disk failed to set read-only again"
                                }
                            }
                        }
                    }
                    $result.message = "Existing partitions found on the selected disk"
                    $result.failed = "true"
                    return $result | ConvertTo-Json
                } else {
                    if ($SetOnline) {
                        try {
                            Set-OperationalStatus -Disk $disk -Deactivate
                        } catch {
                            $OPStatusFailed = $true
                        } finally {
                            if (-not $OPStatusFailed) {
                                if ($Verbose) {
                                    $result.change_log.operational_status = "Disk set online and now offline again"
                                }
                                $result.changed = $true
                            } else {
                                if ($Verbose) {
                                    $result.change_log.operational_status = "Disk failed to set offline again"
                                }
                            }
                        }
                    }
                    if ($SetWriteable) {
                        try {
                            Set-DiskWriteable -Disk $disk -Deactivate
                        } catch {
                            $ROStatusFailed = $true
                        } finally {
                            if (-not $ROStatusFailed) {
                                if ($Verbose) {
                                    $result.change_log.writeable_status = "Disk set writeable and now read-only again"
                                }
                                $result.changed = $true
                            } else {
                                if ($Verbose) {
                                    $result.change_log.writeable_status = "Disk failed to set read-only again"
                                }
                            }
                        }
                    }
                    $result.message = "Existing volumes found on the selected disk"
                    $result.failed = "true"
                    return $result | ConvertTo-Json
                }
            }

            # Check set parameter values
            # Check drive letter and access path
            if ((-not $PSBoundParameters["SetDriveLetter"]) -and ($SetPartitionAccessPath -eq [String]::Empty)) {
                 # Use random drive letter
                    try {
                        $DriveLetter = Get-ChildItem Function:[a-z]: -Name | Where-Object {
                            -not (Test-Path -Path $_)
                        } | Get-Random
                    } catch {
                        if ($SetOnline) {
                            try {
                                Set-OperationalStatus -Disk $disk -Deactivate
                            } catch {
                                $OPStatusFailed = $true
                            } finally {
                                if (-not $OPStatusFailed) {
                                    if ($Verbose) {
                                        $result.change_log.operational_status = "Disk set online and now offline again"
                                    }
                                    $result.changed = $true
                                } else {
                                    if ($Verbose) {
                                        $result.change_log.operational_status = "Disk failed to set offline again"
                                    }
                                }
                            }
                        }
                        if ($SetWriteable) {
                            try {
                                Set-DiskWriteable -Disk $disk -Deactivate
                            } catch {
                                $ROStatusFailed = $true
                            } finally {
                                if (-not $ROStatusFailed) {
                                    if ($Verbose) {
                                        $result.change_log.writeable_status = "Disk set writeable and now read-only again"
                                    }
                                    $result.changed = $true
                                } else {
                                    if ($Verbose) {
                                        $result.change_log.writeable_status = "Disk failed to set read-only again"
                                    }
                                }
                            }
                        }
                        $result.message = "The check to get free drive letters on the target failed"
                        $result.failed = "true"
                        return $result | ConvertTo-Json
                    }
                    if ($DriveLetter) {
                        $SetDriveLetter = $DriveLetter.TrimEnd(":")
                    } else {
                        if ($SetOnline) {
                            try {
                                Set-OperationalStatus -Disk $disk -Deactivate
                            } catch {
                                $OPStatusFailed = $true
                            } finally {
                                if (-not $OPStatusFailed) {
                                    if ($Verbose) {
                                        $result.change_log.operational_status = "Disk set online and now offline again"
                                    }
                                    $result.changed = $true
                                } else {
                                    if ($Verbose) {
                                        $result.change_log.operational_status = "Disk failed to set offline again"
                                    }
                                }
                            }
                        }
                        if ($SetWriteable) {
                            try {
                                Set-DiskWriteable -Disk $disk -Deactivate
                            } catch {
                                $ROStatusFailed = $true
                            } finally {
                                if (-not $ROStatusFailed) {
                                    if ($Verbose) {
                                        $result.change_log.writeable_status = "Disk set writeable and now read-only again"
                                    }
                                    $result.changed = $true
                                } else {
                                    if ($Verbose) {
                                        $result.change_log.writeable_status = "Disk failed to set read-only again"
                                    }
                                }
                            }
                        }
                        $result.message = "No free drive letter left on the target"
                        $result.failed = "true"
                        return $result | ConvertTo-Json
                    }
            } elseif (-not $PSBoundParameters["SetDriveLetter"]) {
                [string]$SetDriveLetter = [string]::Empty
            } else {
                $SetDriveLetter = $PSBoundParameters.SetDriveLetter
            }
            # Check file system
            if ($SetFileSystem -eq "ntfs") {
                if ($GetSize -le 256000) {
                } else {
                    if ($SetOnline) {
                        try {
                            Set-OperationalStatus -Disk $disk -Deactivate
                        } catch {
                            $OPStatusFailed = $true
                        } finally {
                            if (-not $OPStatusFailed) {
                                if ($Verbose) {
                                    $result.change_log.operational_status = "Disk set online and now offline again"
                                }
                                $result.changed = $true
                            } else {
                                if ($Verbose) {
                                    $result.change_log.operational_status = "Disk failed to set offline again"
                                }
                            }
                        }
                    }
                    if ($SetWriteable) {
                        try {
                            Set-DiskWriteable -Disk $disk -Deactivate
                        } catch {
                            $ROStatusFailed = $true
                        } finally {
                            if (-not $ROStatusFailed) {
                                if ($Verbose) {
                                    $result.change_log.writeable_status = "Disk set writeable and now read-only again"
                                }
                                $result.changed = $true
                            } else {
                                if ($Verbose) {
                                    $result.change_log.writeable_status = "Disk failed to set read-only again"
                                }
                            }
                        }
                    }
                    $result.message = "Parameter size with value $($GetSize)gb is not a valid size for ntfs hence the disk can not be formatted with this file system"
                    $result.failed = "true"
                    return $result | ConvertTo-Json
                }
            } elseif ($SetFileSystem -eq "refs") {
                if ($SetAllocationUnitSize -ne 64) {
                    $SetAllocationUnitSize = 64
                    if ($Verbose) {
                        $result.change_log.allocation_unit = "Size was automatically adjusted to 64kb due to FileSystem parameter value refs"
                    }         
                }
            }

            # Initialize / convert disk
            if ($DPartStyle -eq "RAW") {
                if (-not $CheckMode) {
                    if ($DOperSt -eq "Offline") {
                        $SetOnline = $true
                    }
                    if ($DROState -eq "True") {
                        $SetWriteable = $true
                    }
                    # Initialize disk
                    try {
                        Set-Initialized -Disk $disk -PartitionStyle $SetPartitionStyle
                    } catch {
                        $GetDiskFailed = $false
                        $FailDisk = $null
                        if ($SetOnline) {
                            try {
                                $FailDisk = Get-Disk -Number $disk.Number
                            } catch {
                                $GetDiskFailed = $true
                            } finally {
                                if (-not $GetDiskFailed) {
                                    try {
                                        Set-OperationalStatus -Disk $disk -Deactivate
                                    } catch {
                                        $OPStatusFailed = $true
                                    }
                                    if (-not $OPStatusFailed) {
                                        if ($Verbose) {
                                            $result.change_log.operational_status = "Disk was tried to set online during failed disk initalization and set now to it's initial state offline again"
                                        }
                                        $result.changed = $true
                                    } else {
                                        if ($Verbose) {
                                            $result.change_log.operational_status = "Disk was tried to set online during failed disk initalization, set it to it's inital state offline again failed also now"
                                        }
                                    }
                                } else {
                                    if ($Verbose) {
                                        $result.change_log.operational_status = "Disk was tried to set online during failed disk initalization and was now tried to set offline again but disk could not be found anymore"
                                    }
                                }
                            }
                        }
                        if ($SetWriteable) {
                            if (-not $FailDisk) {
                                try {
                                    $FailDisk = Get-Disk -Number $disk.Number
                                } catch {
                                    $GetDiskFailed = $true
                                }
                            }
                            if (-not $GetDiskFailed) {
                                try {
                                    Set-DiskWriteable -Disk $disk -Deactivate
                                } catch {
                                    $ROStatusFailed = $true
                                } finally {
                                    if (-not $ROStatusFailed) {
                                        if ($Verbose) {
                                            $result.change_log.writeable_status = "Disk was tried to set writeable during failed disk initalization and set now to it's initial state read-only again"
                                        }
                                        $result.changed = $true
                                    } else {
                                        if ($Verbose) {
                                            $result.change_log.writeable_status = "Disk was tried to set writeable during failed disk initalization, set it to it's inital state read-only again failed also now"
                                        }
                                    }
                                }
                            } else {
                                if ($Verbose) {
                                    $result.change_log.writeable_status = "Disk was tried to set writeable during failed disk initalization and was now tried to set read-only again but disk could not be found anymore"
                                }
                            }
                        }
                        $result.message = "Failed to initialize the disk: $($_.Exception.Message)"
                        $result.failed = "true"
                        return $result | ConvertTo-Json
                    }
                    if ($Verbose) {
                        $result.change_log.initializing = "Disk initialization successful - Partition style $GetPartitionStyle (partition_style_select) was initalized to $SetPartitionStyle (partition_style_set)"
                    }
                    $result.changed = $true
                } else {
                    $result.change_log.initializing = "Disk with partition style $GetPartitionStyle (partition_style_select) will not be initialized to $SetPartitionStyle (partition_style_set) due to passed -WhatIf switch"
                }
            } else {
                if ($DPartStyle -ne $SetPartitionStyle) {
                    if (-not $CheckMode) {
                        # Convert disk
                        try {
                            Convert-PartitionStyle -Disk $disk -PartitionStyle $SetPartitionStyle
                        } catch {
                            if ($SetOnline) {
                                try {
                                    Set-OperationalStatus -Disk $disk -Deactivate
                                } catch {
                                    $OPStatusFailed = $true
                                } finally {
                                    if (-not $OPStatusFailed) {
                                        if ($Verbose) {
                                            $result.change_log.operational_status = "Disk set online and now offline again"
                                        }
                                        $result.changed = $true
                                    } else {
                                        if ($Verbose) {
                                            $result.change_log.operational_status = "Disk failed to set offline again"
                                        }
                                    }
                                }
                            }
                            if ($SetWriteable) {
                                try {
                                    Set-DiskWriteable -Disk $disk -Deactivate
                                } catch {
                                    $ROStatusFailed = $true
                                } finally {
                                    if (-not $ROStatusFailed) {
                                        if ($Verbose) {
                                            $result.change_log.writeable_status = "Disk set writeable and now read-only again"
                                        }
                                        $result.changed = $true
                                    } else {
                                        if ($Verbose) {
                                            $result.change_log.writeable_status = "Disk failed to set read-only again"
                                        }
                                    }
                                }
                            }
                            $result.message = "Failed to convert the disk: $($_.Exception.Message)"
                            $result.failed = "true"
                            return $result | ConvertTo-Json
                        }
                        if ($Verbose) {
                            $result.change_log.converting = "Partition style $GetPartitionStyle (partition_style_select) was converted to $SetPartitionStyle (partition_style_set)"
                        }
                        $result.changed = $true
                    } else {
                        $result.change_log.converting = "Disk will not be converted from partition style $GetPartitionStyle (partition_style_select) to $SetPartitionStyle (partition_style_set) due to passed -WhatIf switch"
                    }
                }
            }

            # Maintain ShellHWService (not Cmdlet terminating)
            $StopSuccess = $false
            $StopFailed = $false
            $StartFailed = $false
            $CheckFailed = $false
            # Check ShellHWService
            try {
                $Check = Manage-ShellHWService -Action "Check"
            } catch {
                $CheckFailed = $true
            } finally {
                if ($Check) {
                    if (-not $CheckMode) {
                        # Stop ShellHWService
                        try {
                            Manage-ShellHWService -Action "Stop"
                        } catch {
                            $StopFailed = $true
                        } finally {
                            if (-not $StopFailed) {
                                if ($Verbose) {
                                    $result.change_log.shellhw_service_state = "Set from 'Running' to 'Stopped'"
                                }
                                $StopSuccess = $true
                                $result.changed = $true
                            } else {
                                if ($Verbose) {
                                    $result.change_log.shellhw_service_state = "Could not be set from 'Running' to 'Stopped'"
                                }
                            }
                        }
                    } else {
                        $result.change_log.shellhw_service_state = "Service will not be set from 'Running' to 'Stopped' due to passed -WhatIf switch"
                    }
                } elseif ($CheckFailed) {
                    if ($Verbose) {
                        $result.change_log.shellhw_service_state = "Service will not be changed because the check has failed"
                    }
                }
            }

            # Part disk
            if (-not $CheckMode) {
                try {
                    $CPartition = Create-Partition -Disk $disk -SetDriveLetter $SetDriveLetter
                } catch {
                    if ($SetOnline) {
                        try {
                            Set-OperationalStatus -Disk $disk -Deactivate
                        } catch {
                            $OPStatusFailed = $true
                        } finally {
                            if (-not $OPStatusFailed) {
                                if ($Verbose) {
                                    $result.change_log.operational_status = "Disk set online and now offline again"
                                }
                                $result.changed = $true
                            } else {
                                if ($Verbose) {
                                    $result.change_log.operational_status = "Disk failed to set offline again"
                                }
                            }
                        }
                    }
                    if ($SetWriteable) {
                        try {
                            Set-DiskWriteable -Disk $disk -Deactivate
                        } catch {
                            $ROStatusFailed = $true
                        } finally {
                            if (-not $ROStatusFailed) {
                                if ($Verbose) {
                                    $result.change_log.writeable_status = "Disk set writeable and now read-only again"
                                }
                                $result.changed = $true
                            } else {
                                if ($Verbose) {
                                    $result.change_log.writeable_status = "Disk failed to set read-only again"
                                }
                            }
                        }
                    }
                    if ($StopSuccess) {
                        try {
                            Manage-ShellHWService -Action "Start"
                        } catch {
                            $StartFailed = $true
                        } finally {
                            if (-not $StartFailed) {
                                if ($Verbose) {
                                    $result.change_log.shellhw_service_state = "Set from 'Stopped' to 'Running' again"
                                }
                                $result.changed = $true
                            } else {
                                if ($Verbose) {
                                    $result.change_log.shellhw_service_state = "Could not be set from 'Stopped' to 'Running' again"
                                }
                            }
                        }
                    }
                    $result.message = "Failed to create the partition on the disk: $($_.Exception.Message)"
                    $result.failed = "true"
                    return $result | ConvertTo-Json
                }
                if ($Verbose) {
                    if ((-not $PSBoundParameters["SetDriveLetter"]) -and ($SetPartitionAccessPath -eq [String]::Empty)) {
                        $result.change_log.partitioning = "Initial partition $($CPartition.Type) with random drive letter $SetDriveLetter was created successfully on partition style $SetPartitionStyle"
                    } elseif (-not $PSBoundParameters["SetDriveLetter"]) {
                        $result.change_log.partitioning = "Initial partition $($CPartition.Type) with no drive letter was created successfully on partition style $SetPartitionStyle"
                    } else {
                        $result.change_log.partitioning = "Initial partition $($CPartition.Type) with passed drive letter $SetDriveLetter was created successfully on partition style $SetPartitionStyle"
                    }
                }
                $result.changed = $true
            } else {
                $result.change_log.partitioning = "Disk will not be partitioned due to passed -WhatIf switch"
            }

            # Add partition access path
            if (-not $SetPartitionAccessPath -eq [String]::Empty) {
                if (-not $CheckMode) {
                    try {
                        Add-AccessPath -Partition $CPartition -Path $SetPartitionAccessPath
                    } catch {
                        if ($SetOnline) {
                            try {
                                Set-OperationalStatus -Disk $disk -Deactivate
                            } catch {
                                $OPStatusFailed = $true
                            } finally {
                                if (-not $OPStatusFailed) {
                                    if ($Verbose) {
                                        $result.change_log.operational_status = "Disk set online and now offline again"
                                    }
                                    $result.changed = $true
                                } else {
                                    if ($Verbose) {
                                        $result.change_log.operational_status = "Disk failed to set offline again"
                                    }
                                }
                            }
                        }
                        if ($SetWriteable) {
                            try {
                                Set-DiskWriteable -Disk $disk -Deactivate
                            } catch {
                                $ROStatusFailed = $true
                            } finally {
                                if (-not $ROStatusFailed) {
                                    if ($Verbose) {
                                        $result.change_log.writeable_status = "Disk set writeable and now read-only again"
                                    }
                                    $result.changed = $true
                                } else {
                                    if ($Verbose) {
                                        $result.change_log.writeable_status = "Disk failed to set read-only again"
                                    }
                                }
                            }
                        }
                        if ($StopSuccess) {
                            try {
                                Manage-ShellHWService -Action "Start"
                            } catch {
                                $StartFailed = $true
                            } finally {
                                if (-not $StartFailed) {
                                    if ($Verbose) {
                                        $result.change_log.shellhw_service_state = "Set from 'Stopped' to 'Running' again"
                                    }
                                    $result.changed = $true
                                } else {
                                    if ($Verbose) {
                                        $result.change_log.shellhw_service_state = "Could not be set from 'Stopped' to 'Running' again"
                                    }
                                }
                            }
                        }
                        $result.message = "Failed to create partition access path: $($_.Exception.Message)"
                        $result.failed = "true"
                        return $result | ConvertTo-Json
                    }
                    if ($Verbose) {
                        $result.change_log.access_path = "Partition access path $SetPartitionAccessPath was created successfully for partition $($CPartition.Type)"
                    }
                    $result.changed = $true
                } else {
                    $result.change_log.access_path = "Partition access path will not be added to partition due to passed -WhatIf switch"
                }
            }

            # Create volume
            if (-not $CheckMode) {
                [hashtable]$ParamsVol = @{
                    Volume = $CPartition
                    FileSystem = $SetFileSystem
                    FileSystemLabel = $SetLabel
                    FileSystemAllocUnitSize = $SetAllocationUnitSize
                    FileSystemLargeFRS = if ($PSBoundParameters["SetLargeFRS"]) {
                                                                $PSBoundParameters.SetLargeFRS.IsPresent
                                                            } else {
                                                                $false
                                                            }
                    FileSystemShortNames = if ($PSBoundParameters["SetShortNames"]) {
                                                                        $PSBoundParameters.SetShortNames.IsPresent
                                                                    } else {
                                                                        $false
                                                                    }
                    FileSystemIntegrityStreams = if ($PSBoundParameters["SetIntegrityStreams"]) {
                                                        $PSBoundParameters.SetIntegrityStreams.IsPresent
                                                    } else {
                                                        $false
                                                    }
                }
                try {
                    $CVolume = Create-Volume @ParamsVol
                } catch {
                    if ($SetOnline) {
                        try {
                            Set-OperationalStatus -Disk $disk -Deactivate
                        } catch {
                            $OPStatusFailed = $true
                        } finally {
                            if (-not $OPStatusFailed) {
                                if ($Verbose) {
                                    $result.change_log.operational_status = "Disk set online and now offline again"
                                }
                                $result.changed = $true
                            } else {
                                if ($Verbose) {
                                    $result.change_log.operational_status = "Disk failed to set offline again"
                                }
                            }
                        }
                    }
                    if ($SetWriteable) {
                        try {
                            Set-DiskWriteable -Disk $disk -Deactivate
                        } catch {
                            $ROStatusFailed = $true
                        } finally {
                            if (-not $ROStatusFailed) {
                                if ($Verbose) {
                                    $result.change_log.writeable_status = "Disk set writeable and now read-only again"
                                }
                                $result.changed = $true
                            } else {
                                if ($Verbose) {
                                    $result.change_log.writeable_status = "Disk failed to set read-only again"
                                }
                            }
                        }
                    }
                    if ($StopSuccess) {
                        try {
                            Manage-ShellHWService -Action "Start"
                        } catch {
                            $StartFailed = $true
                        } finally {
                            if (-not $StartFailed) {
                                if ($Verbose) {
                                    $result.change_log.shellhw_service_state = "Set from 'Stopped' to 'Running' again"
                                }
                                $result.changed = $true
                            } else {
                                if ($Verbose) {
                                    $result.change_log.shellhw_service_state = "Could not be set from 'Stopped' to 'Running' again"
                                }
                            }
                        }
                    }
                    $result.message = "Failed to create the volume on the disk: $($_.Exception.Message)"
                    $result.failed = "true"
                    return $result | ConvertTo-Json
                }
                if ($Verbose) {
                    $result.change_log.formatting = "Volume $($CVolume.FileSystem) with allocation unit size $SetAllocationUnitSize and label $SetLabel was created successfully on partition $($CPartition.Type)"
                }
                $result.changed = $true
            } else {
                $result.change_log.formatting = "Disk will not be formatted due to passed -WhatIf switch"
            }

            # Finally check if ShellHWService needs to be started again
            if (-not $CheckMode) {
                if ($StopSuccess) {
                    # Start ShellHWService
                    try {
                        Manage-ShellHWService -Action "Start"
                    } catch {
                        $StartFailed = $true
                    } finally {
                        if (-not $StartFailed) {
                            if ($Verbose) {
                                $result.change_log.shellhw_service_state = "Set from 'Stopped' to 'Running' again"
                            }
                            $result.changed = $true
                        } else {
                            if ($Verbose) {
                                $result.change_log.shellhw_service_state = "Could not be set from 'Stopped' to 'Running' again"
                            }
                        }
                    }
                }
            }

            # Return result
            $result.message = "Cmdlet finished successfully"
            return $result | ConvertTo-Json
        }
}
# Define module environment settings
$ErrorActionPreference = "Stop"
Set-StrictMode -Version 2.0

# Export functions and aliases
Set-Alias Manage-Disk Edit-Disk
Export-ModuleMember -Function *-Disk -Alias Manage-Disk