diff --git a/cmd/tk/check.go b/cmd/tk/check.go
index dd467ae1496da8eb7363180ab722a77c99850cbb..35b17485f42dd91b8ba3e9f4ee4411e79e7f0294 100644
--- a/cmd/tk/check.go
+++ b/cmd/tk/check.go
@@ -2,6 +2,7 @@ package main
 
 import (
 	"context"
+	"fmt"
 	"os"
 	"os/exec"
 	"strings"
@@ -14,12 +15,17 @@ import (
 
 var checkCmd = &cobra.Command{
 	Use:   "check",
-	Short: "Check requirements",
+	Short: "Check requirements and installation",
 	Long: `
 The check command will perform a series of checks to validate that
-the local environment is configured correctly.`,
-	Example: `  check --pre`,
-	RunE:    runCheckCmd,
+the local environment is configured correctly and if the installed components are healthy.`,
+	Example: `  # Run pre-installation checks
+  check --pre
+
+  # Run installation checks
+  check
+`,
+	RunE: runCheckCmd,
 }
 
 var (
@@ -37,7 +43,7 @@ func runCheckCmd(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), timeout)
 	defer cancel()
 
-	logAction("starting verification")
+	logAction("checking prerequisites")
 	checkFailed := false
 	if !sshCheck() {
 		checkFailed = true
@@ -51,18 +57,21 @@ func runCheckCmd(cmd *cobra.Command, args []string) error {
 		checkFailed = true
 	}
 
+	if !kubernetesCheck(">=1.14.0") {
+		checkFailed = true
+	}
+
 	if checkPre {
 		if checkFailed {
 			os.Exit(1)
 		}
-		logSuccess("all prerequisites checks passed")
+		logSuccess("prerequisites checks passed")
 		return nil
 	}
 
-	if !kubernetesCheck(">=1.14.0") {
+	if !componentsCheck() {
 		checkFailed = true
 	}
-
 	if checkFailed {
 		os.Exit(1)
 	}
@@ -188,3 +197,19 @@ func kubernetesCheck(version string) bool {
 	logSuccess("kubernetes %s %s", v.String(), version)
 	return true
 }
+
+func componentsCheck() bool {
+	ctx, cancel := context.WithTimeout(context.Background(), timeout)
+	defer cancel()
+
+	for _, deployment := range components {
+		command := fmt.Sprintf("kubectl -n %s rollout status deployment %s --timeout=%s",
+			namespace, deployment, timeout.String())
+		if output, err := utils.execCommand(ctx, ModeCapture, command); err != nil {
+			logFailure("%s: %s", deployment, strings.TrimSuffix(output, "\n"))
+		} else {
+			logSuccess("%s is healthy", deployment)
+		}
+	}
+	return true
+}
diff --git a/cmd/tk/install.go b/cmd/tk/install.go
index 3cda8504599facedb82cac7fd9dfa3e951a1bbee..256e264beb2abcdb68e49005b90e87bc686c7d63 100644
--- a/cmd/tk/install.go
+++ b/cmd/tk/install.go
@@ -15,10 +15,18 @@ var installCmd = &cobra.Command{
 	Use:   "install",
 	Short: "Install the toolkit components",
 	Long: `
-The install command deploys the toolkit components
-on the configured Kubernetes cluster in ~/.kube/config`,
-	Example: `  install --version=master --namespace=gitops-systems`,
-	RunE:    installCmdRun,
+The install command deploys the toolkit components in the specified namespace.
+If a previous version is installed, then an in-place upgrade will be performed.`,
+	Example: `  # Install the latest version in the gitops-systems namespace
+  install --version=master --namespace=gitops-systems
+
+  # Dry-run install for a specific version and a series of components
+  install --dry-run --version=0.0.1 --components="source-controller,kustomize-controller"
+
+  # Dry-run install with manifests preview 
+  install --dry-run --verbose
+`,
+	RunE: installCmdRun,
 }
 
 var (
@@ -57,7 +65,7 @@ func installCmdRun(cmd *cobra.Command, args []string) error {
 
 	logAction("generating install manifests")
 	if kustomizePath == "" {
-		err = genInstallManifests(installVersion, namespace, tmpDir)
+		err = genInstallManifests(installVersion, namespace, components, tmpDir)
 		if err != nil {
 			return fmt.Errorf("install failed: %w", err)
 		}
@@ -103,7 +111,7 @@ func installCmdRun(cmd *cobra.Command, args []string) error {
 	}
 
 	logAction("verifying installation")
-	for _, deployment := range []string{"source-controller", "kustomize-controller"} {
+	for _, deployment := range components {
 		command = fmt.Sprintf("kubectl -n %s rollout status deployment %s --timeout=%s",
 			namespace, deployment, timeout.String())
 		if _, err := utils.execCommand(ctx, applyOutput, command); err != nil {
@@ -138,6 +146,7 @@ fieldSpecs:
 `
 
 var kustomizationTmpl = `---
+{{- $version := .Version }}
 apiVersion: kustomize.config.k8s.io/v1beta1
 kind: Kustomization
 namespace: {{.Namespace}}
@@ -146,9 +155,10 @@ transformers:
 resources:
   - namespace.yaml
   - roles
-  - github.com/fluxcd/toolkit/manifests/bases/source-controller?ref={{.Version}}
-  - github.com/fluxcd/toolkit/manifests/bases/kustomize-controller?ref={{.Version}}
-  - github.com/fluxcd/toolkit/manifests/policies?ref={{.Version}}
+  - github.com/fluxcd/toolkit/manifests/policies?ref={{$version}}
+{{- range .Components }}
+  - github.com/fluxcd/toolkit/manifests/bases/{{.}}?ref={{$version}}
+{{- end }}
 `
 
 var kustomizationRolesTmpl = `---
@@ -159,13 +169,15 @@ resources:
 nameSuffix: -{{.Namespace}}
 `
 
-func genInstallManifests(ver, ns, tmpDir string) error {
+func genInstallManifests(version string, namespace string, components []string, tmpDir string) error {
 	model := struct {
-		Version   string
-		Namespace string
+		Version    string
+		Namespace  string
+		Components []string
 	}{
-		Version:   ver,
-		Namespace: ns,
+		Version:    version,
+		Namespace:  namespace,
+		Components: components,
 	}
 
 	if err := utils.execTemplate(model, namespaceTmpl, path.Join(tmpDir, "namespace.yaml")); err != nil {
diff --git a/cmd/tk/main.go b/cmd/tk/main.go
index 68a954b31ccc410731c0eef16b252975c1cca902..9e6f43cbb58b46487a35ff07bbd8d4de4c52128d 100644
--- a/cmd/tk/main.go
+++ b/cmd/tk/main.go
@@ -28,6 +28,7 @@ var (
 	namespace  string
 	timeout    time.Duration
 	verbose    bool
+	components []string
 	utils      Utils
 )
 
@@ -38,6 +39,9 @@ func init() {
 		"timeout for this operation")
 	rootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "", false,
 		"print generated objects")
+	rootCmd.PersistentFlags().StringSliceVar(&components, "components",
+		[]string{"source-controller", "kustomize-controller"},
+		"list of components, accepts comma-separated values")
 }
 
 func main() {
diff --git a/cmd/tk/uninstall.go b/cmd/tk/uninstall.go
index c32442093297625df169c1c13bbbd08220e788a3..12f0411df5632d57eaf586257211ea140a46739e 100644
--- a/cmd/tk/uninstall.go
+++ b/cmd/tk/uninstall.go
@@ -13,9 +13,14 @@ var uninstallCmd = &cobra.Command{
 	Short: "Uninstall the toolkit components",
 	Long: `
 The uninstall command removes the namespace, cluster roles,
-cluster role bindings and CRDs`,
-	Example: `  uninstall --namespace=gitops-system --crds --dry-run`,
-	RunE:    uninstallCmdRun,
+cluster role bindings and CRDs.`,
+	Example: `  # Dry-run uninstall of all components
+   uninstall --dry-run --namespace=gitops-system
+
+  # Uninstall all components and custom resource definitions
+  uninstall --crds --namespace=gitops-system
+`,
+	RunE: uninstallCmdRun,
 }
 
 var (
diff --git a/cmd/tk/utils.go b/cmd/tk/utils.go
index 1c9ea1c2c9fcc8cf00f1421b7c918f2f92b329c3..c5aaad868a7054286d5d2272ad7271265c087ddf 100644
--- a/cmd/tk/utils.go
+++ b/cmd/tk/utils.go
@@ -49,10 +49,12 @@ func (*Utils) execCommand(ctx context.Context, mode ExecMode, command string) (s
 	}
 
 	if mode == ModeCapture {
-		if output, err := c.CombinedOutput(); err != nil {
-			return "", err
+		c.Stdout = &stdoutBuf
+		c.Stderr = &stderrBuf
+		if err := c.Run(); err != nil {
+			return stderrBuf.String(), err
 		} else {
-			return string(output), nil
+			return stdoutBuf.String(), nil
 		}
 	}