powershellchocolatey

Select Menu for packages to install


i created this script which installs chocolatey and previous in the script "selected" packages (deselection happens with the #). now i want to customize the script in a way that allows to chose the packages to install while running the script. is it possible to create kind of a menu, which allows to select/deselect the packages to be beinstalled while running the script ? maybe someone can give me a hint.

    # Install Chocolatey and All Apps listed in the $Packages variable


       param([switch]$Elevated)
    function Test-Admin {
        $currentUser = New-Object Security.Principal.WindowsPrincipal $([Security.Principal.WindowsIdentity]::GetCurrent())
        $currentUser.IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator)
    }

    if ((Test-Admin) -eq $false)  {
        if ($elevated) {
            # tried to elevate, did not work, aborting
        } else {
            Start-Process powershell.exe -Verb RunAs -ArgumentList ('-noprofile -noexit -file "{0}" -elevated' -f ($myinvocation.MyCommand.Definition))
        }
        exit
    }

    Write-Host "Running with full priviliges" -ForegroundColor Red -BackgroundColor Yellow
    

    pause


Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))



choco install abaclient

   

choco install pdfxchangeeditor -params "'/NoUpdater /NoUpdater'"


# choco install notepadplusplus.install


choco install winrar


choco install firefox

Solution

  • There are of course many ways to create some kind of menu. Here's two ideas for you:

    You could use Out-GridView to select the packages to install like this

    # create an array with all possible installs
    $allPackages = 'winrar', 'notepadplusplus', 'abaclient','firefox' | Sort-Object
    
    $selected = $allPackages | Out-GridView -Title 'Select Packages to install' -PassThru
    if (@($selected).Count) {
        $selected | ForEach-Object { choco install $_ }
    }
    else {
        Write-Host 'Nothing selected..'
    }
    

    Or you could create a selection form of your own like the one below that makes use of a CheckedListBox control:

    # create an array with all possible installs
    $allPackages = 'winrar', 'notepadplusplus', 'abaclient','firefox' | Sort-Object
    $selected    = $null
    
    Add-Type -AssemblyName System.Windows.Forms
    Add-Type -AssemblyName System.Drawing
        
    $form                 = [System.Windows.Forms.Form]::new()
    $form.Text            = 'Select Packages to install'
    $form.Size            = [System.Drawing.Size]::new(500,300)
    $form.StartPosition   = 'CenterScreen'
    $form.FormBorderStyle = 'FixedDialog'
    $form.TopMost         = $true
    
    # create a CheckedListBox control
    $checkedListBox              = [System.Windows.Forms.CheckedListBox]::new()
    $checkedListBox.Location     = [System.Drawing.Size]::new(20,20)
    $checkedListBox.Size         = [System.Drawing.Size]::new(440,200) 
    $checkedListBox.CheckOnClick = $true 
    $checkedListBox.ClearSelected()
    # add the items to install to the list
    foreach ($package in $allPackages) {
        [void]$checkedListBox.Items.Add($package, $false)
    }
    
    $form.Controls.Add($checkedListBox)
    
    # Add a button to the form
    $okButton          = [System.Windows.Forms.Button]::new()
    $okButton.Text     = 'OK'
    $okButton.Location = [System.Drawing.Point]::new(20,230)
    $okButton.Add_Click({
        # capture the chosen items in a variable and close the form
        $script:Selected = $checkedListBox.CheckedItems | ForEach-Object {$_.ToString()}
        $form.DialogResult = [System.Windows.Forms.DialogResult]::OK
        $form.Close()
    })
    
    $form.Controls.Add($okButton)
    $form.AcceptButton = $okButton
    
    # display the form
    [void]$form.ShowDialog()
    # and destroy it when done so it doesn't linger in memory
    $form.Dispose()
    
    if (@($selected).Count) {
        $selected | ForEach-Object { choco install $_ }
    }
    else {
        Write-Host 'Nothing selected..'
    }
    

    Edit

    It seems installing with choco sometimes needs a different install string than just the name of the package. To handle that, I would create a Hashtable with the package name as key and the install string as value:

    $installStrings = @{
        notepadplusplus  = "notepadplusplus.install"
        pdfxchangeeditor = "-params '`"/NoUpdater`"'"  # note the backticks to escape the embedded double-quotes
    }
    

    Then, instead of line $selected | ForEach-Object { choco install $_ }, you do:

    $selected | ForEach-Object { 
        if ($installStrings.ContainsKey($_)) {
            choco install $($installStrings[$_])
        }
        else { choco install $_ }
    }