diff --git a/src/libs/utils/wizard.cpp b/src/libs/utils/wizard.cpp
index 9507425c517b9875b1fb297ac7c273da5fcda4ef..dcfff2959b4458144e2a036621130f5e4f006f5b 100644
--- a/src/libs/utils/wizard.cpp
+++ b/src/libs/utils/wizard.cpp
@@ -30,15 +30,19 @@
 
 #include "wizard.h"
 
+#include "algorithm.h"
 #include "hostosinfo.h"
 #include "qtcassert.h"
 #include "wizardpage.h"
 
+#include <QDialog>
+#include <QDialogButtonBox>
 #include <QHash>
 #include <QIcon>
 #include <QKeyEvent>
 #include <QLabel>
 #include <QMap>
+#include <QScrollArea>
 #include <QVBoxLayout>
 #include <QVariant>
 
@@ -393,6 +397,79 @@ void Wizard::registerFieldName(const QString &name)
     d_ptr->m_fieldNames.insert(name);
 }
 
+QSet<QString> Wizard::fieldNames() const
+{
+    return d_ptr->m_fieldNames;
+}
+
+QHash<QString, QVariant> Wizard::variables() const
+{
+    QHash<QString, QVariant> result;
+    foreach (const QString &f, fieldNames()) {
+        result.insert(f, field(f));
+    }
+    return result;
+}
+
+QString typeOf(const QVariant &v)
+{
+    QString result;
+    switch (v.type()) {
+    case QVariant::Map:
+        result = QLatin1String("Object");
+        break;
+    default:
+        result = QLatin1String(v.typeName());
+    }
+    return result;
+}
+
+void Wizard::showVariables()
+{
+    QString result = QLatin1String("<table>\n  <tr><td>Key</td><td>Type</td><td>Value</td><td>Eval</td></tr>\n");
+    QHash<QString, QVariant> vars = variables();
+    QList<QString> keys = vars.keys();
+    sort(keys);
+    foreach (const QString &key, keys) {
+        const QVariant &v = vars.value(key);
+        result += QLatin1String("  <tr><td>")
+                + key + QLatin1String("</td><td>")
+                + typeOf(v) + QLatin1String("</td><td>")
+                + stringify(v) + QLatin1String("</td><td>")
+                + evaluate(v) + QLatin1String("</td></tr>\n");
+    }
+
+    result += QLatin1String("</table>");
+
+    auto dialog = new QDialog(this);
+    dialog->setMinimumSize(800, 600);
+    auto layout = new QVBoxLayout(dialog);
+    auto scrollArea = new QScrollArea;
+    auto buttons = new QDialogButtonBox(QDialogButtonBox::Ok, Qt::Horizontal);
+
+    auto label = new QLabel(result);
+    label->setWordWrap(true);
+    scrollArea->setWidget(label);
+
+    layout->addWidget(scrollArea);
+    layout->addWidget(buttons);
+
+    connect(buttons, &QDialogButtonBox::accepted, dialog, &QDialog::accept);
+    connect(dialog, &QDialog::finished, dialog, &QObject::deleteLater);
+
+    dialog->show();
+}
+
+QString Wizard::stringify(const QVariant &v) const
+{
+    return v.toString();
+}
+
+QString Wizard::evaluate(const QVariant &v) const
+{
+    return stringify(v);
+}
+
 bool Wizard::event(QEvent *event)
 {
     if (event->type() == QEvent::ShortcutOverride) {
diff --git a/src/libs/utils/wizard.h b/src/libs/utils/wizard.h
index 1bafdb658e0a9d87060d675d97f60241a1f0e7ce..f6ffab99f52265bba56de4a1e75b84344b497c27 100644
--- a/src/libs/utils/wizard.h
+++ b/src/libs/utils/wizard.h
@@ -72,12 +72,20 @@ public:
     // will return true for all fields registered via Utils::WizardPage::registerFieldWithName(...)
     bool hasField(const QString &name) const;
     void registerFieldName(const QString &name);
+    QSet<QString> fieldNames() const;
+
+    virtual QHash<QString, QVariant> variables() const;
+
+public slots:
+    void showVariables();
 
 signals:
     void nextClicked(); /* workaround for QWizard behavior where page->initialize is
                          * called before currentIdChanged */
 
 protected:
+    virtual QString stringify(const QVariant &v) const;
+    virtual QString evaluate(const QVariant &v) const;
     bool event(QEvent *event);
 
 private slots:
diff --git a/src/plugins/coreplugin/iwizardfactory.cpp b/src/plugins/coreplugin/iwizardfactory.cpp
index d17f29b4fddd8c90c025a211d1fbcb0b4b11638f..f3548e19fb6e1e3892cfac9d8201e76a89586650 100644
--- a/src/plugins/coreplugin/iwizardfactory.cpp
+++ b/src/plugins/coreplugin/iwizardfactory.cpp
@@ -155,6 +155,7 @@ namespace {
 static QList<IFeatureProvider *> s_providerList;
 QList<IWizardFactory *> s_allFactories;
 QList<IWizardFactory::FactoryCreator> s_factoryCreators;
+QAction *s_inspectWizardAction = 0;
 bool s_areFactoriesLoaded = false;
 bool s_isWizardRunning = false;
 }
@@ -256,11 +257,15 @@ Utils::Wizard *IWizardFactory::runWizard(const QString &path, QWidget *parent, c
     if (wizard) {
         // Connect while wizard exists:
         connect(m_action, &QAction::triggered, wizard, [wizard]() { ICore::raiseWindow(wizard); });
+        connect(s_inspectWizardAction, &QAction::triggered,
+                wizard, [wizard]() { wizard->showVariables(); });
         connect(wizard, &Utils::Wizard::finished, [wizard]() {
             s_isWizardRunning = false;
+            s_inspectWizardAction->setEnabled(false);
             ICore::validateNewDialogIsRunning();
             wizard->deleteLater();
         });
+        s_inspectWizardAction->setEnabled(true);
         wizard->show();
         Core::ICore::registerWindow(wizard, Core::Context("Core.NewWizard"));
     } else {
@@ -380,4 +385,7 @@ void IWizardFactory::initialize()
     connect(resetAction, &QAction::triggered, &IWizardFactory::clearWizardFactories);
     connect(ICore::instance(), &ICore::newItemDialogRunningChanged, resetAction,
             [resetAction]() { resetAction->setEnabled(!ICore::isNewItemDialogRunning()); });
+
+    s_inspectWizardAction = new QAction(tr("Inspect Wizard State"), ActionManager::instance());
+    ActionManager::registerAction(s_inspectWizardAction, "Wizard.Inspect");
 }
diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizard.cpp b/src/plugins/projectexplorer/jsonwizard/jsonwizard.cpp
index 8e242260dea61bece491ba9c651391ad153969d8..dd5bd007ce274d725c4e0573dfe6b9802a713ba6 100644
--- a/src/plugins/projectexplorer/jsonwizard/jsonwizard.cpp
+++ b/src/plugins/projectexplorer/jsonwizard/jsonwizard.cpp
@@ -189,6 +189,16 @@ void JsonWizard::removeAttributeFromAllFiles(Core::GeneratedFile::Attribute a)
     }
 }
 
+QHash<QString, QVariant> JsonWizard::variables() const
+{
+    QHash<QString, QVariant> result = Wizard::variables();
+    foreach (const QByteArray &p, dynamicPropertyNames()) {
+        QString key = QString::fromUtf8(p);
+        result.insert(key, value(key));
+    }
+    return result;
+}
+
 void JsonWizard::accept()
 {
     auto page = qobject_cast<Utils::WizardPage *>(currentPage());
@@ -273,6 +283,18 @@ void JsonWizard::handleError(const QString &message)
     Core::MessageManager::write(message, Core::MessageManager::ModeSwitch);
 }
 
+QString JsonWizard::stringify(const QVariant &v) const
+{
+    if (v.type() == QVariant::StringList)
+        return stringListToArrayString(v.toStringList(), &m_expander);
+    return Wizard::stringify(v);
+}
+
+QString JsonWizard::evaluate(const QVariant &v) const
+{
+    return m_expander.expand(stringify(v));
+}
+
 void JsonWizard::openFiles(const JsonWizard::GeneratorFiles &files)
 {
     QString errorMessage;
diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizard.h b/src/plugins/projectexplorer/jsonwizard/jsonwizard.h
index fba16e66b3af1daecd52c758ba03bee8bda3c591..edc61009858bcf2d3e122c1b4eac041ad4a159f0 100644
--- a/src/plugins/projectexplorer/jsonwizard/jsonwizard.h
+++ b/src/plugins/projectexplorer/jsonwizard/jsonwizard.h
@@ -84,6 +84,8 @@ public:
 
     void removeAttributeFromAllFiles(Core::GeneratedFile::Attribute a);
 
+    QHash<QString, QVariant> variables() const override;
+
 signals:
     void preGenerateFiles(); // emitted before files are generated (can happen several times!)
     void postGenerateFiles(const JsonWizard::GeneratorFiles &files); // emitted after commitToFileList was called.
@@ -104,6 +106,8 @@ private slots:
     void handleError(const QString &message);
 
 private:
+    QString stringify(const QVariant &v) const override;
+    QString evaluate(const QVariant &v) const override ;
     void openFiles(const GeneratorFiles &files);
 
     QList<JsonWizardGenerator *> m_generators;