Search code examples
windowspowershellinputinputbox

How can I make my script stop when clicked on the cancel Button?


I am working on a script that gives you prompts for copying whole folderstructures including the ACLs (permissions)
My Question now is how can I make it so that when I click on the cancel button in the popup that it actually cancels?

I am working with powershell :)

**#----------------------Source Drive and Folder---------------------#
[System.Reflection.Assembly]::LoadWithPartialName('Microsoft.VisualBasic') | Out-Null
$sourceDrive = [Microsoft.VisualBasic.Interaction]::InputBox("Please enter the source drive for copying `n(e.g: C)", "source drive", "")
$sourceFolder = [Microsoft.VisualBasic.Interaction]::InputBox("Please enter the source folder for copying `n(e.g: Folder\Something)", "source folder", "")
#----------------------Source Drive and Folder---------------------#

#-------------------Destination Drive and Folder-------------------#
[System.Reflection.Assembly]::LoadWithPartialName('Microsoft.VisualBasic') | Out-Null
$destinationDrive = [Microsoft.VisualBasic.Interaction]::InputBox("Please enter the destination drive for copying `n(e.g: D)", "destination drive", "")
$destinationFolder = [Microsoft.VisualBasic.Interaction]::InputBox("Please enter the destination folder for copying `n(e.g: Folder1\Something2)", "destination folder", "")
#-------------------Destination Drive and Folder-------------------#

#--------------------Create new Folder for Copy--------------------#
$createNewFolder = [Microsoft.VisualBasic.Interaction]::InputBox("Do you want to create a new folder in this directory? `n(e.g: y/n)", "Create new folder", "")

if($createNewFolder -eq "n"){
    xcopy "$sourceDrive`:\$sourceFolder" "$destinationDrive`:\$destinationFolder" /O /X /E /H /K
}elseif($createNewFolder -eq "y") {
    [System.Reflection.Assembly]::LoadWithPartialName('Microsoft.VisualBasic') | Out-Null
    $newFolder = [Microsoft.VisualBasic.Interaction]::InputBox("Please enter the name of the folder `n(e.g: somefolder)", "New folder", "")
    xcopy "$sourceDrive`:\$sourceFolder" "$destinationDrive`:\$newfolder\$destinationFolder" /O /X /E /H /K
}else {

}
#--------------------Create new Folder for Copy--------------------#

#xcopy "$sourceDrive`:\$sourceFolder" "$destinationDrive`:\$destinationFolder" /O /X /E /H /K**

This was posted in powershell.org too: https://powershell.org/forums/topic/how-can-i-make-my-script-stop-when-clicked-on-the-cancel-button-2/

Thanks in advance

Martin


Solution

  • Personally, I don't see why you want to use all those InputBoxes, where you can suffice with just using a FolderBrowser dialog (twice).
    By using that dialog, you can also be sure the user doesn't just type in anything and you don't have to check every step of the way.

    Below function Get-FolderPath is a helper function to wrap the calling of the BrowseForFolder dialog to make your life easier.

    function Get-FolderPath {
        # Show an Open Folder Dialog and return the directory selected by the user.
        [CmdletBinding()]
        param (
            [Parameter(Mandatory=$false, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, Position=0)]
            [string]$Message = "Select a directory.",
    
            $InitialDirectory = [System.Environment+SpecialFolder]::MyComputer,
    
            [switch]$ShowNewFolderButton
        )
    
        # Browse Dialog Options:
        # https://learn.microsoft.com/en-us/windows/win32/api/shlobj_core/ns-shlobj_core-browseinfoa
        $browserForFolderOptions = 0x00000041                                  # BIF_RETURNONLYFSDIRS -bor BIF_NEWDIALOGSTYLE
        if (!$ShowNewFolderButton) { $browserForFolderOptions += 0x00000200 }  # BIF_NONEWFOLDERBUTTON
    
        $browser = New-Object -ComObject Shell.Application
        # To make the dialog topmost, you need to supply the Window handle of the current process
        [intPtr]$handle = [System.Diagnostics.Process]::GetCurrentProcess().MainWindowHandle
    
        # see: https://msdn.microsoft.com/en-us/library/windows/desktop/bb773205(v=vs.85).aspx
    
        # ShellSpecialFolderConstants for InitialDirectory:
        # https://learn.microsoft.com/en-us/windows/win32/api/shldisp/ne-shldisp-shellspecialfolderconstants#constants
    
        $folder = $browser.BrowseForFolder($handle, $Message, $browserForFolderOptions, $InitialDirectory)
    
        $result = if ($folder) { $folder.Self.Path } else { $null }
    
        # Release and remove the used Com object from memory
        [System.Runtime.Interopservices.Marshal]::ReleaseComObject($browser) | Out-Null
        [System.GC]::Collect()
        [System.GC]::WaitForPendingFinalizers()
    
        return $result
    }
    

    Having that in place at the top of your script, the code could be as simple as:

    $source = Get-FolderPath -Message 'Please enter the source folder to copy'
    # if $null is returned, the user cancelled the dialog
    if ($source) { 
        # the sourcefolder is selected, now lets do this again for the destination path
        # by specifying switch '-ShowNewFolderButton', you allow the user to create a new folder
        $destination = Get-FolderPath -Message 'Please enter the destination path to copy to' -ShowNewFolderButton
        if ($destination) {
            # both source and destination are now known, so start copying
            xcopy "$source" "$destination" /O /X /E /H /K
        }
    }
    

    If the user presses 'Cancel' on any of the both times you call Get-FolderPath, the script exits