diff --git a/README.md b/README.md
index de96a67dddf1937395dabdf83225293e862aa10f..33343685a6c9d5d80793d723ee535bae49056e82 100644
--- a/README.md
+++ b/README.md
@@ -47,6 +47,7 @@ List of supported Commands:
     vmlistedit          List VMs that can be edited (regex matching).
     vmlisteditaccess    List VMs that can have their VM access edited (regex matching).
     vmlistdel           List VMs that can be deleted (regex matching).
+    vmlistexportdir     List VMs that can have a directory exported (regex matching).
     vmcred2pdf          Create a PDF with the credentials required to attach to running VMs (regex matching).
     vmstart             Start one or more VMs (regex matching).
     vmstop              Stop one or more VMs (regex matching).
@@ -56,6 +57,7 @@ List of supported Commands:
     vmdel               Delete one or more VMs (regex matching).
     vmsetaccess         Set a user's VM access in one or more VMs (regex matching).
     vmdelaccess         Delete a user's VM access in one or more VMs (regex matching).
+    vmexportdir         Export one or more VMs' directory into one or more tar archives. Create one archive per VM (regex matching).
     tpllist             List available templates (regex matching).
     tplcreate           Create a template, either from an existing VM or from a .qcow file.
     tpldel              Delete one or more templates (regex matching).
@@ -273,6 +275,11 @@ Generate `exam_vms.pdf` with the credentials required to connect to all running
 nexus-client vmcred2pdf "exam prog sys" output.pdf
 ```
 
+Extract and download the `/home` directory of all VMs matching "exam prog sys" (each directory is saved in a `.tar` archive named after the VM's ID):
+```
+nexus-client vmlistexportdir "exam prog sys" /home
+```
+
 List all available templates:
 ```
 nexus-client tpllist .
diff --git a/src/client_cli/cmdVM/helper.go b/src/client_cli/cmdVM/helper.go
index c62a4140843ce4ab1e27480405ec2de1635e80ca..7d3121ee4afa7f3f8c067aa04a0aba2917692cfd 100644
--- a/src/client_cli/cmdVM/helper.go
+++ b/src/client_cli/cmdVM/helper.go
@@ -52,17 +52,13 @@ func (vm *VM)String() string {
 	return string(output)
 }
 
-func printUsage(c cmd.Command, action string, showLongOutputFlag bool) {
+func printRegexUsage(c cmd.Command) {
 	u.PrintlnErr(c.GetDesc())
-	longOutputFlag := ""
-	if showLongOutputFlag {
-		longOutputFlag = " [-l]"
-	}
-	u.PrintlnErr("Usage: ",c.GetName(),longOutputFlag+" [ID ...] [regex ...]")
-	if showLongOutputFlag {
-		u.PrintlnErr("Use \"-l\" to specify detailed VMs output.")
-	}
-	u.PrintlnErr("Only VMs matching the specified IDs or regexes will be "+action+".")
+	u.PrintlnErr("Usage: ",c.GetName()," [ID ...] [regex ...]")
+}
+
+func printRegexUsageDetails() {
+	u.PrintlnErr("The action only applies to VMs matching the specified IDs or regexes.")
 	const usage string = `Any number of IDs or regexes can be specified.
 The regex only matches the VM's name and is case-insensitive.
 Regex examples:
diff --git a/src/client_cli/cmdVM/vmAttach.go b/src/client_cli/cmdVM/vmAttach.go
index c46abdc89b680454162e215b5ecc8a18bb225375..ff3ee6b4ac42f9b27cdfb5792142bb62d7feb09d 100644
--- a/src/client_cli/cmdVM/vmAttach.go
+++ b/src/client_cli/cmdVM/vmAttach.go
@@ -27,7 +27,8 @@ func (cmd *Attach)GetDesc() string {
 }
 
 func (cmd *Attach)PrintUsage() {
-	printUsage(cmd, "attached to", false)
+	printRegexUsage(cmd)
+	printRegexUsageDetails()
 }
 
 func (cmd *Attach)Run(args []string) int {
@@ -52,7 +53,7 @@ func (cmd *Attach)Run(args []string) int {
 	}
 
 	if len(vms) == 0 {
-		u.PrintlnErr("No VMs to attach to!")
+		u.PrintlnErr("No match.")
 		return 1
 	}
 
diff --git a/src/client_cli/cmdVM/vmCred2pdf.go b/src/client_cli/cmdVM/vmCred2pdf.go
index 6cb6ba039a3bc0f6c27d4b7f0078377c51a6912c..f1cefa4333045823ea5fc0a6438132e96c9fc246 100644
--- a/src/client_cli/cmdVM/vmCred2pdf.go
+++ b/src/client_cli/cmdVM/vmCred2pdf.go
@@ -21,14 +21,7 @@ func (cmd *Cred2pdf)GetDesc() string {
 func (cmd *Cred2pdf)PrintUsage() {
 	u.PrintlnErr(cmd.GetDesc())
 	u.PrintlnErr("Usage: ",cmd.GetName()," [ID ...] [regex ...] pdfile")
-	u.PrintlnErr("Only VMs that can be attached to and matching the specified IDs or regexes will be listed.")
-	const usage string = `Any number of IDs or regexes can be specified.
-The regex only matches the VM's name and is case-insensitive.
-Regex examples:
-""    -> matches any VMs
-"."   -> matches any VMs
-"bla" -> matches any VMs containing "bla" in their name`
-	u.PrintlnErr(usage)
+	printRegexUsageDetails()
 }
 
 func (cmd *Cred2pdf)Run(args []string) int {
@@ -47,7 +40,7 @@ func (cmd *Cred2pdf)Run(args []string) int {
 	}
 
 	if len(vms) == 0 {
-		u.PrintlnErr("No VMs to retrieve credentials from!")
+		u.PrintlnErr("No match.")
 		return 1
 	}
 
diff --git a/src/client_cli/cmdVM/vmDel.go b/src/client_cli/cmdVM/vmDel.go
index f1b893f286e0236e811d6c7aff9f2c1888733a87..71a27f720ad56bedc66c9c5eff7e417572513d0c 100644
--- a/src/client_cli/cmdVM/vmDel.go
+++ b/src/client_cli/cmdVM/vmDel.go
@@ -18,7 +18,8 @@ func (cmd *Del)GetDesc() string {
 }
 
 func (cmd *Del)PrintUsage() {
-	printUsage(cmd, "deleted", false)
+	printRegexUsage(cmd)
+	printRegexUsageDetails()
 }
 
 func (cmd *Del)Run(args []string) int {
@@ -38,7 +39,7 @@ func (cmd *Del)Run(args []string) int {
 	}
 
 	if len(vms) == 0 {
-		u.PrintlnErr("No VMs to delete!")
+		u.PrintlnErr("No match.")
 		return 1
 	}
 
diff --git a/src/client_cli/cmdVM/vmDelAccess.go b/src/client_cli/cmdVM/vmDelAccess.go
index 01163151ca6715d1c5b2423b6b561f7a07e5c279..3c80b2e0d5d6280b254f30fcb3ee83dedc4b8a2a 100644
--- a/src/client_cli/cmdVM/vmDelAccess.go
+++ b/src/client_cli/cmdVM/vmDelAccess.go
@@ -59,7 +59,7 @@ func (cmd *DelAccess)Run(args []string) int {
 	}
 
 	if len(vms) == 0 {
-		u.PrintlnErr("No VMs to delete user's VM access!")
+		u.PrintlnErr("No match.")
 		return 1
 	}
 
diff --git a/src/client_cli/cmdVM/vmEdit.go b/src/client_cli/cmdVM/vmEdit.go
index 007fd464b37e47d7b3687a6be6ce58cbd84d94cc..dc81d3c486d708424cbee761c049a7091dc79d8d 100644
--- a/src/client_cli/cmdVM/vmEdit.go
+++ b/src/client_cli/cmdVM/vmEdit.go
@@ -72,7 +72,7 @@ func (cmd *Edit)Run(args []string) int {
 	}
 
 	if len(vms) == 0 {
-		u.PrintlnErr("No VMs to edit!")
+		u.PrintlnErr("No match.")
 		return 1
 	}
 
diff --git a/src/client_cli/cmdVM/vmExportDir.go b/src/client_cli/cmdVM/vmExportDir.go
new file mode 100644
index 0000000000000000000000000000000000000000..b9c56947a4fdf79cd90310665616d25c73b60efa
--- /dev/null
+++ b/src/client_cli/cmdVM/vmExportDir.go
@@ -0,0 +1,78 @@
+package cmdVM
+
+import (
+	u "nexus-client/utils"
+	g "nexus-client/globals"
+)
+
+type ExportDir struct {
+    Name string
+}
+
+type vmExportDirParams struct {
+	Dir string
+}
+
+func (cmd *ExportDir)GetName() string {
+	return cmd.Name
+}
+ 
+func (cmd *ExportDir)GetDesc() string {
+	return "Export one or more VMs' directory into one or more tar archives. Create one archive per VM (regex matching)."
+}
+
+func (cmd *ExportDir)PrintUsage() {
+	u.PrintlnErr(cmd.GetDesc())
+	u.PrintlnErr("Usage: ",cmd.GetName()," [ID ...] [regex ...] dir")
+	u.PrintlnErr("\"dir\" is the directory in the VM to export into a tar archive named after the VM ID.")
+	printRegexUsageDetails()
+}
+
+func (cmd *ExportDir)Run(args []string) int {
+	client := g.GetInstance().Client
+	host := g.GetInstance().Host
+
+	argc := len(args)
+	if argc < 2 {
+		cmd.PrintUsage()
+		return 1
+	}
+
+	dir := args[argc-1]
+
+	vms, err := getFilteredVMs("/vms/exportdir", args[:argc-1])
+	if err != nil {
+		u.PrintlnErr("Error: "+err.Error())
+		return 1
+	}
+
+	if len(vms) == 0 {
+		u.PrintlnErr("No match.")
+		return 1
+	}
+
+	params := &vmExportDirParams { Dir: dir }
+
+	statusCode := 0
+
+	client.SetAllowGetMethodPayload(true)
+
+	for _, vm := range(vms) {
+		uuid := vm.ID.String()
+		outputFile := uuid+".tar"
+		resp, err := client.R().SetOutput(outputFile).SetBody(params).Get(host+"/vms/"+uuid+"/exportdir")
+		if err != nil {
+			u.PrintlnErr("Failed exporting "+dir+" from VM \""+vm.Name+"\" | "+uuid+" : "+err.Error())
+			statusCode = 1
+		} else {
+			if resp.IsSuccess() {
+				u.Println("Successfully exported "+dir+" from VM \""+vm.Name+"\" ("+uuid+") into "+outputFile)
+			} else {
+				u.PrintlnErr("Failed exporting "+dir+" from VM \""+vm.Name+"\" | "+uuid+" : "+resp.Status()+": "+resp.String())
+				statusCode = 1
+			}
+		}
+	}
+
+	return statusCode
+}
diff --git a/src/client_cli/cmdVM/vmList.go b/src/client_cli/cmdVM/vmList.go
index ba904a02650a2965c79a4174e59e927945ac2055..d8b1fe158b8209ae5f3d72776cc5b8d149dc013c 100644
--- a/src/client_cli/cmdVM/vmList.go
+++ b/src/client_cli/cmdVM/vmList.go
@@ -1,5 +1,9 @@
 package cmdVM
 
+import (
+	u "nexus-client/utils"
+)
+
 type List struct {
     Name string
 }
@@ -13,7 +17,10 @@ func (cmd *List)GetDesc() string {
 }
 
 func (cmd *List)PrintUsage() {
-	printUsage(cmd, "listed", true)
+	u.PrintlnErr(cmd.GetDesc())
+	u.PrintlnErr("Usage: ",cmd.GetName(), " [-l] [ID ...] [regex ...]")
+	u.PrintlnErr("Use \"-l\" to specify detailed VMs output.")
+	printRegexUsageDetails()
 }
 
 func (cmd *List)Run(args []string) int {
diff --git a/src/client_cli/cmdVM/vmListAttach.go b/src/client_cli/cmdVM/vmListAttach.go
index 5953aabb341c6da16db2d474ae31aa1b74b25323..bc5a3adf7ec0b13a4df0c2440ef59241ab6923e2 100644
--- a/src/client_cli/cmdVM/vmListAttach.go
+++ b/src/client_cli/cmdVM/vmListAttach.go
@@ -13,7 +13,8 @@ func (cmd *ListAttach)GetDesc() string {
 }
 
 func (cmd *ListAttach)PrintUsage() {
-	printUsage(cmd, "listed", false)
+	printRegexUsage(cmd)
+	printRegexUsageDetails()
 }
 
 func (cmd *ListAttach)Run(args []string) int {
diff --git a/src/client_cli/cmdVM/vmListDel.go b/src/client_cli/cmdVM/vmListDel.go
index 9506db80a13827cdc11020d0350b3c33ec9f774d..0e22640a3a7110db041a99bbad8f7ca4c1731950 100644
--- a/src/client_cli/cmdVM/vmListDel.go
+++ b/src/client_cli/cmdVM/vmListDel.go
@@ -13,7 +13,8 @@ func (cmd *ListDel)GetDesc() string {
 }
 
 func (cmd *ListDel)PrintUsage() {
-	printUsage(cmd, "listed", false)
+	printRegexUsage(cmd)
+	printRegexUsageDetails()
 }
 
 func (cmd *ListDel)Run(args []string) int {
diff --git a/src/client_cli/cmdVM/vmListEdit.go b/src/client_cli/cmdVM/vmListEdit.go
index 73d4096df3a9dff9abc80486def3d069ff5a135c..7d45a9bc1ace3b13dad8b5f2f65fb9b5628226d7 100644
--- a/src/client_cli/cmdVM/vmListEdit.go
+++ b/src/client_cli/cmdVM/vmListEdit.go
@@ -13,7 +13,8 @@ func (cmd *ListEdit)GetDesc() string {
 }
 
 func (cmd *ListEdit)PrintUsage() {
-	printUsage(cmd, "listed", false)
+	printRegexUsage(cmd)
+	printRegexUsageDetails()
 }
 
 func (cmd *ListEdit)Run(args []string) int {
diff --git a/src/client_cli/cmdVM/vmListEditAccess.go b/src/client_cli/cmdVM/vmListEditAccess.go
index 78d9a59d2c4c3bf377a2ca42f77b1b4de8e7a3ee..7de1addf76588ca6c804622d5280a30e5ffa360c 100644
--- a/src/client_cli/cmdVM/vmListEditAccess.go
+++ b/src/client_cli/cmdVM/vmListEditAccess.go
@@ -13,7 +13,8 @@ func (cmd *ListEditAccess)GetDesc() string {
 }
 
 func (cmd *ListEditAccess)PrintUsage() {
-	printUsage(cmd, "listed", false)
+	printRegexUsage(cmd)
+	printRegexUsageDetails()
 }
 
 func (cmd *ListEditAccess)Run(args []string) int {
diff --git a/src/client_cli/cmdVM/vmListExportDir.go b/src/client_cli/cmdVM/vmListExportDir.go
new file mode 100644
index 0000000000000000000000000000000000000000..d6e56535bf5f408da2260308653f6c0abe1f52ae
--- /dev/null
+++ b/src/client_cli/cmdVM/vmListExportDir.go
@@ -0,0 +1,22 @@
+package cmdVM
+
+type ListExportDir struct{
+    Name string
+}
+
+func (cmd *ListExportDir)GetName() string {
+	return cmd.Name
+}
+ 
+func (cmd *ListExportDir)GetDesc() string {
+	return "List VMs that can have a directory exported (regex matching)."
+}
+
+func (cmd *ListExportDir)PrintUsage() {
+	printRegexUsage(cmd)
+	printRegexUsageDetails()
+}
+
+func (cmd *ListExportDir)Run(args []string) int {
+	return printFilteredVMs(cmd, args, "/vms/exportdir")
+}
diff --git a/src/client_cli/cmdVM/vmListStart.go b/src/client_cli/cmdVM/vmListStart.go
index 16038bad8f8c6d81bc3e580c44aea461fcf079e0..2a04678561ef9b522e66dc0a2bf98ead5916a19b 100644
--- a/src/client_cli/cmdVM/vmListStart.go
+++ b/src/client_cli/cmdVM/vmListStart.go
@@ -13,7 +13,8 @@ func (cmd *ListStart)GetDesc() string {
 }
 
 func (cmd *ListStart)PrintUsage() {
-	printUsage(cmd, "listed", false)
+	printRegexUsage(cmd)
+	printRegexUsageDetails()
 }
 
 func (cmd *ListStart)Run(args []string) int {
diff --git a/src/client_cli/cmdVM/vmListStop.go b/src/client_cli/cmdVM/vmListStop.go
index 76846b43bea6c1dbc7549144af01a8008b69606f..9eb6d26f2587ea4cf3d961ddba12e35c6535826a 100644
--- a/src/client_cli/cmdVM/vmListStop.go
+++ b/src/client_cli/cmdVM/vmListStop.go
@@ -13,7 +13,8 @@ func (cmd *ListStop)GetDesc() string {
 }
 
 func (cmd *ListStop)PrintUsage() {
-	printUsage(cmd, "listed", false)
+	printRegexUsage(cmd)
+	printRegexUsageDetails()
 }
 
 func (cmd *ListStop)Run(args []string) int {
diff --git a/src/client_cli/cmdVM/vmSetAccess.go b/src/client_cli/cmdVM/vmSetAccess.go
index 08159bec143fc118a4363cf31f460bf8174525b0..50cd240eed12d45f4f0c238716878227d384406f 100644
--- a/src/client_cli/cmdVM/vmSetAccess.go
+++ b/src/client_cli/cmdVM/vmSetAccess.go
@@ -56,7 +56,7 @@ func (cmd *SetAccess)Run(args []string) int {
 	}
 
 	if len(vms) == 0 {
-		u.PrintlnErr("No VMs to set user's VM access!")
+		u.PrintlnErr("No match.")
 		return 1
 	}
 
diff --git a/src/client_cli/cmdVM/vmStart.go b/src/client_cli/cmdVM/vmStart.go
index 3ed02d2e82ad7718a293a63755f6e67d670f24b4..33c73407f500f575aaa8c53c860334c818824123 100644
--- a/src/client_cli/cmdVM/vmStart.go
+++ b/src/client_cli/cmdVM/vmStart.go
@@ -18,7 +18,8 @@ func (cmd *Start)GetDesc() string {
 }
 
 func (cmd *Start)PrintUsage() {
-	printUsage(cmd, "started", false)
+	printRegexUsage(cmd)
+	printRegexUsageDetails()
 }
 
 func (cmd *Start)Run(args []string) int {
@@ -38,7 +39,7 @@ func (cmd *Start)Run(args []string) int {
 	}
 
 	if len(vms) == 0 {
-		u.PrintlnErr("No VMs to start!")
+		u.PrintlnErr("No match.")
 		return 1
 	}
 
diff --git a/src/client_cli/cmdVM/vmStop.go b/src/client_cli/cmdVM/vmStop.go
index 73180e1076201fdd0cec97353d9acd110ebf496d..079221df1bc7fc96c0b330f5887b682991ba9356 100644
--- a/src/client_cli/cmdVM/vmStop.go
+++ b/src/client_cli/cmdVM/vmStop.go
@@ -18,7 +18,8 @@ func (cmd *Stop)GetDesc() string {
 }
 
 func (cmd *Stop)PrintUsage() {
-	printUsage(cmd, "stopped", false)
+	printRegexUsage(cmd)
+	printRegexUsageDetails()
 }
 
 func (cmd *Stop)Run(args []string) int {
@@ -38,7 +39,7 @@ func (cmd *Stop)Run(args []string) int {
 	}
 
 	if len(vms) == 0 {
-		u.PrintlnErr("No VMs to stop!")
+		u.PrintlnErr("No match.")
 		return 1
 	}
 
diff --git a/src/client_cli/nexus-client.go b/src/client_cli/nexus-client.go
index d78d84d8662b46ec85cf0a1061fe423d46b616c8..dd724943c4223d7fad571c68110a99cb6bc991ef 100644
--- a/src/client_cli/nexus-client.go
+++ b/src/client_cli/nexus-client.go
@@ -31,6 +31,7 @@ var cmdList = []cmd.Command {
 	&cmdVM.ListEdit{"vmlistedit"},
 	&cmdVM.ListEditAccess{"vmlisteditaccess"},
 	&cmdVM.ListDel{"vmlistdel"},
+	&cmdVM.ListExportDir{"vmlistexportdir"},
 
 	&cmdVM.Cred2pdf{"vmcred2pdf"},
 
@@ -42,6 +43,7 @@ var cmdList = []cmd.Command {
 	&cmdVM.Del{"vmdel"},
 	&cmdVM.SetAccess{"vmsetaccess"},
 	&cmdVM.DelAccess{"vmdelaccess"},
+	&cmdVM.ExportDir{"vmexportdir"},
 
 	&cmdTemplate.List{"tpllist"},
 	&cmdTemplate.Create{"tplcreate"},