diff --git a/image_creator/dialog_main.py b/image_creator/dialog_main.py
index 4c456a94e222aae7dd9be41a2f408ad782447bec..cf9d4b07fb8cc841804cac2f9385aff75a894db9 100644
--- a/image_creator/dialog_main.py
+++ b/image_creator/dialog_main.py
@@ -21,11 +21,13 @@ snf-image-creator program. The main function will create a dialog where the
 user is asked if he wants to use the program in expert or wizard mode.
 """
 
+from __future__ import unicode_literals
+
 import dialog
 import sys
 import os
 import signal
-import optparse
+import argparse
 import types
 import termios
 import traceback
@@ -278,27 +280,22 @@ def main():
         sys.stderr.write("Error: You must run %s as root\n" % PROGNAME)
         sys.exit(2)
 
-    usage = "Usage: %prog [options] [<input_media>]"
-    parser = optparse.OptionParser(version=version, usage=usage)
-    parser.add_option("-l", "--logfile", type="string", dest="logfile",
-                      default=None, help="log all messages to FILE",
-                      metavar="FILE")
-    parser.add_option("--no-snapshot", dest="snapshot", default=True,
-                      help="don't snapshot the input media. (THIS IS "
-                      "DANGEROUS AS IT WILL ALTER THE ORIGINAL MEDIA!!!)",
-                      action="store_false")
-    parser.add_option("--syslog", dest="syslog", default=False,
-                      help="log to syslog", action="store_true")
-    parser.add_option("--tmpdir", type="string", dest="tmp", default=None,
-                      help="create large temporary image files under DIR",
-                      metavar="DIR")
-
-    opts, args = parser.parse_args(sys.argv[1:])
-
-    if len(args) > 1:
-        parser.error("Wrong number of arguments")
-
-    media = args[0] if len(args) == 1 else None
+    description = "Dialog-based tool for creating OS images"
+    parser = argparse.ArgumentParser(version=version, description=description)
+    parser.add_argument("-l", "--logfile", dest="logfile", metavar="FILE",
+                        default=None, help="log all messages to FILE")
+    parser.add_argument("--no-snapshot", dest="snapshot", default=True,
+                        help="don't snapshot the input media. (THIS IS "
+                        "DANGEROUS AS IT WILL ALTER THE ORIGINAL MEDIA!!!)",
+                        action="store_false")
+    parser.add_argument("--syslog", dest="syslog", default=False,
+                        help="log to syslog", action="store_true")
+    parser.add_argument("--tmpdir", dest="tmp", default=None, metavar="DIR",
+                        help="create large temporary image files under DIR")
+    parser.add_argument("source", metavar="SOURCE", default=None, nargs='?',
+                        help="Image file, block device or /")
+
+    opts = parser.parse_args()
 
     if opts.tmp is not None and not os.path.isdir(opts.tmp):
         parser.error("Directory: `%s' specified with --tmpdir is not valid"
@@ -314,7 +311,7 @@ def main():
         # Save the terminal attributes
         attr = termios.tcgetattr(sys.stdin.fileno())
         try:
-            ret = dialog_main(media, logfile=logfile, tmpdir=opts.tmp,
+            ret = dialog_main(opts.source, logfile=logfile, tmpdir=opts.tmp,
                               snapshot=opts.snapshot, syslog=opts.syslog)
         finally:
             # Restore the terminal attributes. If an error occurs make sure
diff --git a/image_creator/dialog_menu.py b/image_creator/dialog_menu.py
index ff83652b32490a9b4ed277ce87efcbe512b58371..077d4eeda7db06a3ea7fbba4af2b95cde1e1d79b 100644
--- a/image_creator/dialog_menu.py
+++ b/image_creator/dialog_menu.py
@@ -287,8 +287,8 @@ def register_image(session):
 
                 # Upload metadata file
                 out.info("Uploading metadata file ...", False)
-                metastring = unicode(json.dumps(cloud['registered'],
-                                                indent=4, ensure_ascii=False))
+                metastring = json.dumps(cloud['registered'], indent=4,
+                                        ensure_ascii=False)
                 kamaki.upload(StringIO.StringIO(metastring),
                               size=len(metastring),
                               remote_path="%s.meta" % remote,
diff --git a/image_creator/dialog_util.py b/image_creator/dialog_util.py
index fe9001e18a9ce0e18701772b96c6abb0c3658d29..987bc99a8fa1028374c584cb8798c881e6b4c4be 100644
--- a/image_creator/dialog_util.py
+++ b/image_creator/dialog_util.py
@@ -148,8 +148,8 @@ def extract_metadata_string(session):
         for key in session['task_metadata']:
             metadata[key] = 'yes'
 
-    return unicode(json.dumps({'properties': metadata,
-                               'disk-format': 'diskdump'}, ensure_ascii=False))
+    return json.dumps({'properties': metadata, 'disk-format': 'diskdump'},
+                      ensure_ascii=False)
 
 
 def extract_image(session):
diff --git a/image_creator/main.py b/image_creator/main.py
index 13be9ab3f1e24cc48fe1bba47e9e81fed2c72c68..ecc2a3fd35788342829d27cbea7ec458ab42a9e6 100644
--- a/image_creator/main.py
+++ b/image_creator/main.py
@@ -20,6 +20,8 @@
 snf-image-creator program.
 """
 
+from __future__ import unicode_literals
+
 from image_creator import __version__ as version
 from image_creator.disk import Disk
 from image_creator.util import FatalError
@@ -30,7 +32,7 @@ from image_creator.output.syslog import SyslogOutput
 from image_creator.kamaki_wrapper import Kamaki, ClientError, CONTAINER
 import sys
 import os
-import optparse
+import argparse
 import StringIO
 import signal
 import json
@@ -41,136 +43,167 @@ import time
 import re
 
 
-def check_writable_dir(option, opt_str, value, parser):
+class CheckWritableDir(argparse.Action):
     """Check if a directory is writable"""
-    dirname = os.path.dirname(value)
-    name = os.path.basename(value)
-    if dirname and not os.path.isdir(dirname):
-        raise FatalError("`%s' is not an existing directory" % dirname)
-
-    if not name:
-        raise FatalError("`%s' is not a valid file name" % dirname)
-
-    setattr(parser.values, option.dest, value)
-
-
-def parse_options(input_args):
-    """Parse input parameters"""
-    usage = "Usage: %prog [options] <input_media>"
-    parser = optparse.OptionParser(version=version, usage=usage)
-
-    parser.add_option("-a", "--authentication-url", dest="url", type="string",
-                      default=None, help="use this authentication URL when "
-                      "uploading/registering images")
-
-    parser.add_option("--add-timestamp", dest="timestamp", default=False,
-                      help="Add a timestamp when outputting messages",
-                      action="store_true")
-
-    parser.add_option("--allow-unsupported", dest="allow_unsupported",
-                      help="proceed with the image creation even if the media "
-                      "is not supported", default=False, action="store_true")
-
-    parser.add_option("-c", "--cloud", dest="cloud", type="string",
-                      default=None, help="use this saved cloud account to "
-                      "authenticate against a cloud when "
-                      "uploading/registering images")
-
-    parser.add_option("--container", dest="container", type="string",
-                      default=CONTAINER, help="Upload files to CONTAINER "
-                      "[default: %s]" % CONTAINER)
-
-    parser.add_option("--disable-sysprep", dest="disabled_syspreps",
-                      help="prevent SYSPREP operation from running on the "
-                      "input media", default=[], action="append",
-                      metavar="SYSPREP")
-
-    parser.add_option("--enable-sysprep", dest="enabled_syspreps", default=[],
-                      help="run SYSPREP operation on the input media",
-                      action="append", metavar="SYSPREP")
+    def __call__(self, parser, namespace, value, option):
 
-    parser.add_option("-f", "--force", dest="force", default=False,
-                      action="store_true",
-                      help="overwrite output files if they exist")
+        if getattr(namespace, self.dest):
+            raise argparse.ArgumentError(self,
+                                         "Argument defined multiple times")
 
-    parser.add_option("--host-run", dest="host_run", default=[],
-                      help="mount the media in the host and run a script "
-                      "against the guest media. This option may be defined "
-                      "multiple times. The script's working directory will be "
-                      "the guest's root directory. BE CAREFUL! DO NOT USE "
-                      "ABSOLUTE PATHS INSIDE THE SCRIPT! YOU MAY HARM YOUR "
-                      "SYSTEM!", metavar="SCRIPT", action="append")
+        dirname = os.path.dirname(value)
+        name = os.path.basename(value)
 
-    parser.add_option("--install-virtio", dest="virtio", type="string",
-                      help="install VirtIO drivers hosted under DIR "
-                      "(Windows only)", metavar="DIR")
+        if dirname and not os.path.isdir(dirname):
+            raise argparse.ArgumentError(
+                self, "`%s' is not an existing directory" % dirname)
+        if not os.access(dirname, os.W_OK):
+            raise argparse.ArgumentError(
+                self, "`%s' is not writable" % dirname)
+        if not name:
+            raise argparse.ArgumentError(
+                self, "`%s' is not a valid file name" % dirname)
 
-    parser.add_option("-m", "--metadata", dest="metadata", default=[],
-                      help="add custom KEY=VALUE metadata to the image",
-                      action="append", metavar="KEY=VALUE")
+        setattr(namespace, self.dest, value.decode(sys.stdin.encoding))
 
-    parser.add_option("--no-snapshot", dest="snapshot", default=True,
-                      help="don't snapshot the input media. (THIS IS "
-                      "DANGEROUS AS IT WILL ALTER THE ORIGINAL MEDIA!!!)",
-                      action="store_false")
 
-    parser.add_option("--no-sysprep", dest="sysprep", default=True,
-                      help="don't perform any system preparation operation",
-                      action="store_false")
+class AddKeyValue(argparse.Action):
+    """Add key value options"""
+    def __call__(self, parser, namespace, value, option):
 
-    parser.add_option("-o", "--outfile", type="string", dest="outfile",
-                      default=None, action="callback", metavar="FILE",
-                      callback=check_writable_dir, help="dump image to FILE")
+        dest = getattr(namespace, self.dest)
+        if not dest:
+            dest = {}
 
-    parser.add_option("--print-metadata", dest="print_metadata", default=False,
-                      help="print the detected image metadata",
-                      action='store_true')
-
-    parser.add_option("--print-syspreps", dest="print_syspreps", default=False,
-                      help="print the enabled and disabled system preparation "
-                      "operations for this input media", action="store_true")
-
-    parser.add_option("--print-sysprep-params", dest="print_sysprep_params",
-                      default=False, action="store_true",
-                      help="print the defined system preparation parameters "
-                      "for this input media")
-
-    parser.add_option("--public", dest="public", default=False,
-                      help="register image with the cloud as public",
-                      action="store_true")
-
-    parser.add_option("-r", "--register", dest="register", type="string",
-                      default=False, metavar="IMAGENAME",
-                      help="register the image with a cloud as IMAGENAME")
-
-    parser.add_option("-s", "--silent", dest="silent", default=False,
-                      help="output only errors", action="store_true")
-
-    parser.add_option('--syslog', dest="syslog", default=False,
-                      help="log to syslog", action="store_true")
-
-    parser.add_option("--sysprep-param", dest="sysprep_params", default=[],
-                      help="add KEY=VALUE system preparation parameter",
-                      action="append")
-
-    parser.add_option("-t", "--token", dest="token", type="string",
-                      default=None, help="use this authentication token when "
-                      "uploading/registering images")
-
-    parser.add_option("--tmpdir", dest="tmp", type="string", default=None,
-                      help="create large temporary image files under DIR",
-                      metavar="DIR")
+        value = value.decode(sys.stdin.encoding)
+        try:
+            key, val = value.split('=', 1)
+        except ValueError:
+            raise argparse.ArgumentError(
+                self, "`%s' is not in KEY=VALUE format." % value)
+        dest[key.upper()] = val
 
-    parser.add_option("-u", "--upload", dest="upload", type="string",
-                      default=False, metavar="FILENAME",
-                      help="upload the image to the cloud with name FILENAME")
+        setattr(namespace, self.dest, dest)
 
-    options, args = parser.parse_args(input_args)
 
-    if len(args) != 1:
-        parser.error('Wrong number of arguments')
+def parse_options():
+    """Parse input parameters"""
+    description = "Command-line tool for creating OS images"
+    parser = argparse.ArgumentParser(version=version, description=description)
+
+    parser.add_argument("source", metavar="SOURCE",
+                        help="Image file, block device or /")
+    parser.add_argument(
+        "-a", "--authentication-url", dest="url", default=None,
+        help="use this authentication URL when uploading/registering images")
+
+    parser.add_argument(
+        "--add-timestamp", dest="timestamp", default=False,
+        help="Add a timestamp when outputting messages", action="store_true")
+
+    parser.add_argument(
+        "--allow-unsupported", dest="allow_unsupported",
+        help="proceed with the image creation even if the media is not "
+        "supported", default=False, action="store_true")
+
+    parser.add_argument(
+        "-c", "--cloud", dest="cloud", default=None,
+        help="use this saved cloud account to authenticate against a cloud "
+             "when uploading/registering images")
+
+    parser.add_argument(
+        "--container", dest="container", default=CONTAINER,
+        help="Upload files to CONTAINER [default: %s]" % CONTAINER)
+
+    parser.add_argument(
+        "--disable-sysprep", dest="disabled_syspreps",
+        help="prevent SYSPREP operation from running on the input media",
+        default=[], action="append", metavar="SYSPREP")
+
+    parser.add_argument(
+        "--enable-sysprep", dest="enabled_syspreps", default=[],
+        help="run SYSPREP operation on the input media", action="append",
+        metavar="SYSPREP")
+
+    parser.add_argument(
+        "-f", "--force", dest="force", default=False, action="store_true",
+        help="overwrite output files if they exist")
+
+    parser.add_argument(
+        "--host-run", dest="host_run", default=[],
+        help="mount the media in the host and run a script against the guest "
+             "media. This option may be defined multiple times. The script's "
+             "working directory will be the guest's root directory. BE "
+             "CAREFUL! DO NOT USE ABSOLUTE PATHS INSIDE THE SCRIPT! YOU MAY "
+             "HARM YOUR SYSTEM!",
+        metavar="SCRIPT", action="append")
+
+    parser.add_argument(
+        "--install-virtio", dest="virtio", metavar="DIR",
+        help="install VirtIO drivers hosted under DIR (Windows only)")
+
+    parser.add_argument(
+        "-m", "--metadata", dest="metadata", default={}, action=AddKeyValue,
+        help="add custom KEY=VALUE metadata to the image", metavar="KEY=VALUE")
+
+    parser.add_argument(
+        "--no-snapshot", dest="snapshot", default=True,
+        help="don't snapshot the input media. (THIS IS DANGEROUS AS IT WILL "
+             "ALTER THE ORIGINAL MEDIA!!!)", action="store_false")
+
+    parser.add_argument("--no-sysprep", dest="sysprep", default=True,
+                        help="don't perform any system preparation operation",
+                        action="store_false")
+
+    parser.add_argument("-o", "--outfile", dest="outfile", default=None,
+                        action=CheckWritableDir, metavar="FILE",
+                        help="dump image to FILE")
+
+    parser.add_argument("--print-metadata", dest="print_metadata",
+                        action='store_true', default=False,
+                        help="print the detected image metadata")
+
+    parser.add_argument(
+        "--print-syspreps", dest="print_syspreps", default=False,
+        help="print the enabled and disabled system preparation operations "
+             "for this input media", action="store_true")
+
+    parser.add_argument(
+        "--print-sysprep-params", dest="print_sysprep_params", default=False,
+        help="print the defined system preparation parameters for this input "
+        "media", action="store_true")
+
+    parser.add_argument("--public", dest="public", default=False,
+                        help="register image with the cloud as public",
+                        action="store_true")
+
+    parser.add_argument("-r", "--register", dest="register", default=False,
+                        metavar="IMAGENAME",
+                        help="register the image with a cloud as IMAGENAME")
+
+    parser.add_argument("-s", "--silent", dest="silent", default=False,
+                        help="output only errors", action="store_true")
+
+    parser.add_argument('--syslog', dest="syslog", default=False,
+                        help="log to syslog", action="store_true")
+
+    parser.add_argument("--sysprep-param", dest="sysprep_params", default={},
+                        help="add KEY=VALUE system preparation parameter",
+                        action=AddKeyValue)
+
+    parser.add_argument(
+        "-t", "--token", dest="token", default=None,
+        help="use this authentication token when uploading/registering images")
+
+    parser.add_argument("--tmpdir", dest="tmp", default=None, metavar="DIR",
+                        help="create large temporary image files under DIR")
+
+    parser.add_argument(
+        "-u", "--upload", dest="upload", default=None, metavar="FILENAME",
+        help="upload the image to the cloud with name FILENAME")
+
+    options = parser.parse_args()
 
-    options.source = args[0]
     if not os.path.exists(options.source):
         parser.error("Input media `%s' is not accessible" % options.source)
 
@@ -188,32 +221,23 @@ def parse_options(input_args):
         parser.error("The directory `%s' specified with --tmpdir is not valid"
                      % options.tmp)
 
+    # Convert input attributes to unicode
+    for opt in ('url', 'cloud', 'container', 'outfile', 'register', 'token',
+                'tmp', 'upload', 'virtio'):
+        attr = getattr(options, opt)
+        if attr:
+            setattr(options, opt, attr.decode(sys.stdin.encoding))
+
+    options.host_run = [h.decode(sys.stdin.encoding) for h in options.host_run]
+
     metadata_regexp = re.compile('^[A-Za-z_]+$')
-    meta = {}
     for m in options.metadata:
-        try:
-            key, value = m.split('=', 1)
-        except ValueError:
-            parser.error("Metadata option: `%s' is not in KEY=VALUE format." %
-                         m)
-        if not re.match(metadata_regexp, key):
+        if not re.match(metadata_regexp, m):
             parser.error("Metadata key: `%s' is not valid. Allowed characters "
-                         "for key: [a-zA-Z0-9_]." % key)
-        meta[key.upper()] = value
-    options.metadata = meta
-
-    sysprep_params = {}
-    for p in options.sysprep_params:
-        try:
-            key, value = p.split('=', 1)
-        except ValueError:
-            parser.error("Sysprep parameter option: `%s' is not in KEY=VALUE "
-                         "format." % p)
-        sysprep_params[key] = value
+                         "for key: [a-zA-Z0-9_]." % m)
 
     if options.virtio is not None:
-        sysprep_params['virtio'] = options.virtio
-    options.sysprep_params = sysprep_params
+        options.sysprep_params['virtio'] = options.virtio
 
     if options.outfile is None and not options.upload and not \
             options.print_syspreps and not options.print_sysprep_params \
@@ -331,6 +355,11 @@ def image_creator(options, out):
             else:
                 out.warn("Sysprep: `%s' does not exist. Can't enable it." %
                          name)
+        if image.is_unsupported():
+            image.meta['EXCLUDE_ALL_TASKS'] = "yes"
+
+        # Add command line metadata to the collected ones...
+        image.meta.update(options.metadata)
 
         if options.print_syspreps:
             image.os.print_syspreps()
@@ -386,17 +415,11 @@ def image_creator(options, out):
         if options.sysprep:
             image.os.do_sysprep()
 
-        if image.is_unsupported():
-            image.meta['EXCLUDE_ALL_TASKS'] = "yes"
-
-        # Add command line metadata to the collected ones...
-        image.meta.update(options.metadata)
-
         checksum = image.md5()
 
-        metastring = unicode(json.dumps(
-            {'properties': image.meta,
-             'disk-format': 'diskdump'}, ensure_ascii=False))
+        metastring = json.dumps(
+            {'properties': image.meta, 'disk-format': 'diskdump'},
+            ensure_ascii=False)
 
         if options.outfile is not None:
             if os.path.realpath(options.outfile) == '/dev/null':
@@ -476,7 +499,7 @@ def image_creator(options, out):
 
 def main():
     """Main entry point"""
-    options = parse_options(sys.argv[1:])
+    options = parse_options()
 
     if options.silent:
         out = SilentOutput(colored=sys.stderr.isatty(),
diff --git a/image_creator/os_type/__init__.py b/image_creator/os_type/__init__.py
index c40d2080dcfdcaf94d5fb4c51916f7c28c4810ab..c9cd73375434f7c5ca87b6a23f6992084abc77e8 100644
--- a/image_creator/os_type/__init__.py
+++ b/image_creator/os_type/__init__.py
@@ -445,7 +445,7 @@ class OSBase(object):
                                        "%s" % param.description))
             self.out.info("TYPE:".ljust(13) + "%s%s" %
                           ("list:" if param.is_list else "", param.type))
-            self.out.info("VALUE:".ljust(13) +
+            self.out.info("VALUE:".ljust(13) + "%s" %
                           ("\n".ljust(14).join(param.value) if param.is_list
                            else param.value))
             self.out.info()
diff --git a/setup.py b/setup.py
index 2d7e10a26aa9f63b82ecf6ff6044d88465337cc7..4bf663a11c4d2b6c5fc3681e8b3da24c92764da9 100755
--- a/setup.py
+++ b/setup.py
@@ -37,7 +37,8 @@ setup(
     license='GNU GPLv3',
     packages=find_packages(),
     include_package_data=True,
-    install_requires=['sh', 'ansicolors', 'progress>=1.0.2', 'kamaki>=0.9'],
+    install_requires=['sh', 'ansicolors', 'progress>=1.0.2', 'kamaki>=0.9',
+                      'argparse'],
     # Unresolvable dependencies:
     #   pysendfile|py-sendfile, hivex, guestfs, parted, rsync,
     entry_points={