Functions/Public/Start-DeployUserCerts.ps1


function Start-DeployUserCerts {
    [CmdletBinding(DefaultParameterSetName = 'gui')]
    param (
        # Type of certs to distribute, All, New or byUsername
        [Parameter(HelpMessage = 'Type of cert deployment to initiate', ParameterSetName = 'cli', Mandatory)]
        [ValidateSet("All", "New", "ByUsername")]
        [system.String]
        $type,
        # username
        [Parameter(HelpMessage = 'The JumpCloud username of a user to deploy a certificate', ParameterSetName = 'cli')]
        [System.String]
        $username,
        # Force invoke commands after generation
        [Parameter(HelpMessage = 'Switch to force invoke generated commands on systems', ParameterSetName = 'cli')]
        [switch]
        $forceInvokeCommands,
        # Force invoke commands after generation
        [Parameter(HelpMessage = 'Switch to force generate new commands on systems', ParameterSetName = 'cli')]
        [switch]
        $forceGenerateCommands
    )

    if ($Global:JCRSettings.sessionImport -eq $false) {
        Get-JCRGlobalVars
        $Global:JCRSettings.sessionImport = $true
    }

    # Import the users.json file and convert to PSObject
    $userArray = Get-UserJsonData
    # identify users that need their certs still deployed
    $usersWithoutLatestCert = Get-UsersThatNeedCertWork -userData $userArray
    # set the script root variable to use for parallel functions:
    $JCRScriptRoot = $Global:JCRScriptRoot

    do {
        switch ($PSCmdlet.ParameterSetName) {
            'gui' {
                Show-DistributionMenu -CertObjectArray $userArray.certInfo -usersThatNeedCert $usersWithoutLatestCert.count -totalUserCount $userArray.count
                $confirmation = Read-Host "Please make a selection"

                # This can be updated later if necessary but for now if using the GUI, the $forceGenerateCommands switch will always be false
                # Thus the GUI will never overwrite commands unless the SHA1 value does not match the local cert SHA1
                switch ($forceGenerateCommands) {
                    $true {
                        $generateCommands = $true
                    }
                    $false {
                        $generateCommands = $false
                    }
                }
            }
            'cli' {
                $confirmationMap = @{
                    'All'        = '1';
                    'New'        = '2';
                    "ByUsername" = '3';
                }
                $confirmation = $confirmationMap[$type]
                # if force invoke is set, invoke the commands after generation:
                switch ($forceInvokeCommands) {
                    $true {
                        $invokeCommands = $true
                    }
                    $false {
                        $invokeCommands = $false
                    }
                }
                switch ($forceGenerateCommands) {
                    $true {
                        $generateCommands = $true
                    }
                    $false {
                        $generateCommands = $false
                    }
                }
            }
        }

        switch ($confirmation) {
            '1' {
                # case for all users
                switch ($PSCmdlet.ParameterSetName) {
                    'gui' {
                        $invokeCommands = Get-ResponsePrompt -message "Would you like to invoke commands after they've been generated?"
                        if (($invokeCommands -ne $true) -And ($invokeCommands -ne $false)) {
                            return
                        }
                    }
                }

                # set thread safe variables:
                $resultArray = [System.Collections.Concurrent.ConcurrentBag[object]]::new()
                $workDoneArray = [System.Collections.Concurrent.ConcurrentBag[object]]::new()

                $userArray | Foreach-Object -ThrottleLimit 20 -Parallel {
                    # set the required variables
                    $JCAPIKEY = $using:JCAPIKEY
                    $JCORGID = $using:JCORGID
                    $JCRScriptRoot = $using:JCRScriptRoot

                    # Import the private functions
                    $Private = @( Get-ChildItem -Path "$JCRScriptRoot/Functions/Private/*.ps1" -Recurse )
                    foreach ($Import in $Private) {
                        Try {
                            . $Import.FullName
                        } Catch {
                            Write-Error -Message "Failed to import function $($Import.FullName): $_"
                        }
                    }

                    # set the required global variables
                    $global:JCRConfig = @{
                        'radiusDirectory' = @{
                            value = $using:JCRConfig.radiusDirectory.value
                        }
                        'certType'        = @{
                            value = $using:JCRConfig.certType.value
                        }
                        'openSSLBinary'   = @{
                            value = $using:JCRConfig.openSSLBinary.value
                        }
                    }
                    $global:JCRSettings = @{
                        userAgent = $using:JCRSettings.userAgent
                    }
                    $Global:JCRUsers = $using:JCRUsers
                    $Global:JCRSystems = $using:JCRSystems
                    $Global:JCRAssociations = $using:JCRAssociations
                    $Global:JCRRadiusMembers = $using:JCRRadiusMembers
                    $Global:JCRCertHash = $using:JCRCertHash

                    # set the thread safe variables
                    $resultArray = $using:resultArray
                    $workDoneArray = $using:workDoneArray

                    # deploy user certs:
                    $result, $workDone = Deploy-UserCertificate -userObject $_ -forceInvokeCommands $using:invokeCommands -forceGenerateCommands $using:generateCommands
                    # keep track of results & work done
                    $resultArray.Add($result)
                    $WorkDoneArray.Add($workDone)
                }

                # update the userTable:
                foreach ($item in $workDoneArray) {
                    Set-UserTable -index $item.userIndex -commandAssociationsObject $item.commandAssociationsObject -certInfoObject $item.certInfoObject
                }

                # print the progress:
                $resultCount = $resultArray.Count
                $resultItemCount = 1
                foreach ($item in $resultArray) {
                    Show-RadiusProgress -completedItems ($resultItemCount) -totalItems $resultArray.Count -ActionText "Distributing Radius Certificates" -previousOperationResult $item
                    $resultItemCount++
                }

                # return after an action if cli, else stay in function
                switch ($PSCmdlet.ParameterSetName) {
                    'gui' {
                        Show-StatusMessage -Message "Finished Distributing Certificates"
                    }
                    'cli' {
                        return
                    }
                }
            }
            '2' {
                # case for new users; users that do not have certinfo marked as already deployed (i.e. users with new certs or un-deployed certs)
                switch ($PSCmdlet.ParameterSetName) {
                    'gui' {
                        $invokeCommands = Get-ResponsePrompt -message "Would you like to invoke commands after they've been generated?"
                        if (($invokeCommands -ne $true) -And ($invokeCommands -ne $false)) {
                            return
                        }
                    }
                }
                if (-Not $usersWithoutLatestCert) {
                    $usersWithoutLatestCert = Get-UsersThatNeedCertWork -userData $userArray
                }

                # set thread safe variables:
                $resultArray = [System.Collections.Concurrent.ConcurrentBag[object]]::new()
                $workDoneArray = [System.Collections.Concurrent.ConcurrentBag[object]]::new()
                # foreach user:
                $usersWithoutLatestCert | Foreach-Object -ThrottleLimit 20 -Parallel {
                    # set the required variables
                    $JCAPIKEY = $using:JCAPIKEY
                    $JCORGID = $using:JCORGID
                    $JCRScriptRoot = $using:JCRScriptRoot

                    # set the required global variables
                    $global:JCRConfig = @{
                        'radiusDirectory' = @{
                            value = $using:JCRConfig.radiusDirectory.value
                        }
                        'certType'        = @{
                            value = $using:JCRConfig.certType.value
                        }
                        'openSSLBinary'   = @{
                            value = $using:JCRConfig.openSSLBinary.value
                        }
                    }
                    $global:JCRSettings = @{
                        userAgent = $using:JCRSettings.userAgent
                    }
                    $Global:JCRUsers = $using:JCRUsers
                    $Global:JCRSystems = $using:JCRSystems
                    $Global:JCRAssociations = $using:JCRAssociations
                    $Global:JCRRadiusMembers = $using:JCRRadiusMembers
                    $Global:JCRCertHash = $using:JCRCertHash

                    # set the thread safe variables
                    $resultArray = $using:resultArray
                    $workDoneArray = $using:workDoneArray

                    # Import the private functions
                    $Private = @( Get-ChildItem -Path "$JCRScriptRoot/Functions/Private/*.ps1" -Recurse )
                    foreach ($Import in $Private) {
                        Try {
                            . $Import.FullName
                        } Catch {
                            Write-Error -Message "Failed to import function $($Import.FullName): $_"
                        }
                    }

                    # deploy user certs:
                    $result, $workDone = Deploy-UserCertificate -userObject $_ -forceInvokeCommands $using:invokeCommands -forceGenerateCommands $using:generateCommands
                    # keep track of results & work done
                    $resultArray.Add($result)
                    $WorkDoneArray.Add($workDone)
                }

                # update the userTable:
                foreach ($item in $workDoneArray) {
                    Set-UserTable -index $item.userIndex -commandAssociationsObject $item.commandAssociationsObject -certInfoObject $item.certInfoObject
                }

                # print the progress:
                $resultCount = $resultArray.Count
                $resultItemCount = 1
                foreach ($item in $resultArray) {
                    Show-RadiusProgress -completedItems ($resultItemCount) -totalItems $resultArray.Count -ActionText "Distributing Radius Certificates" -previousOperationResult $item
                    $resultItemCount++
                }
                # return after an action if cli, else stay in function
                switch ($PSCmdlet.ParameterSetName) {
                    'gui' {
                        Show-StatusMessage -Message "Finished Distributing Certificates"
                    }
                    'cli' {
                        return
                    }
                }
            }
            '3' {
                # case for users by username
                switch ($PSCmdlet.ParameterSetName) {
                    'gui' {
                        try {
                            Clear-Variable -Name "ConfirmUser" -ErrorAction Ignore
                        } catch {
                            New-Variable -Name "ConfirmUser" -Value $null
                        }
                        while (-not $confirmUser) {
                            $confirmationUser = Read-Host "Enter the Username of the user (or '@exit' to return to menu)"
                            if ($confirmationUser -eq '@exit') {
                                break
                            }
                            try {
                                $confirmUser = Test-UserFromHash -username $confirmationUser -debug
                            } catch {
                                Write-Warning "User specified $confirmationUser was not found within the Radius Server Membership Lists"
                            }
                        }
                    }
                    'cli' {
                        $confirmUser = Test-UserFromHash -username $username -debug
                    }
                }
                if ($confirmUser) {
                    # Get the userobject + index from users.json
                    $userObject, $userIndex = Get-UserFromTable -userID $confirmUser.id
                    # Add user to a list for processing
                    $UserSelectionArray = $userArray[$userIndex]
                    # write-warning "Selected User: $($UserSelectionArray.username) with userID: $($UserSelectionArray.userID)"
                    # Process existing commands/ Generate new commands/ Deploy new Certificate
                    switch ($PSCmdlet.ParameterSetName) {
                        'gui' {
                            $result, $workDone = Deploy-UserCertificate -userObject $UserSelectionArray -prompt
                        }
                        'cli' {
                            $result, $workDone = Deploy-UserCertificate -userObject $UserSelectionArray -forceInvokeCommands $invokeCommands -forceGenerateCommands $generateCommands
                        }
                    }
                    # update user json
                    Set-UserTable -index $workDone.userIndex -commandAssociationsObject $workDone.commandAssociationsObject -certInfoObject $workDone.certInfoObject

                    # show progress
                    Show-RadiusProgress -completedItems $UserSelectionArray.count -totalItems $UserSelectionArray.Count -ActionText "Distributing Radius Certificates" -previousOperationResult $result
                }
                # return after an action if cli, else stay in function
                switch ($PSCmdlet.ParameterSetName) {
                    'gui' {
                        Show-StatusMessage -Message "Finished Distributing Certificates"
                    }
                    'cli' {
                        return
                    }
                }
            }
        }
    } while ($confirmation -ne 'E')
}