diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index 76b98fcf81a12c3c14debba3d63864aa4ef59d97..e47a2eba407aa0aee8c2e6038733a6752b3083d7 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -381,6 +381,8 @@ set(SRCS
   cmVariableWatch.h
   cmVersion.cxx
   cmVersion.h
+  cmWorkingDirectory.cxx
+  cmWorkingDirectory.h
   cmXMLParser.cxx
   cmXMLParser.h
   cmXMLSafe.cxx
diff --git a/Source/cmWorkingDirectory.cxx b/Source/cmWorkingDirectory.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..99c9ba86a44611aae49cad2ccc69dc1c9fc3c60c
--- /dev/null
+++ b/Source/cmWorkingDirectory.cxx
@@ -0,0 +1,24 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#include "cmWorkingDirectory.h"
+
+#include "cmSystemTools.h"
+
+cmWorkingDirectory::cmWorkingDirectory(std::string const& newdir)
+{
+  this->OldDir = cmSystemTools::GetCurrentWorkingDirectory();
+  cmSystemTools::ChangeDirectory(newdir);
+}
+
+cmWorkingDirectory::~cmWorkingDirectory()
+{
+  this->Pop();
+}
+
+void cmWorkingDirectory::Pop()
+{
+  if (!this->OldDir.empty()) {
+    cmSystemTools::ChangeDirectory(this->OldDir);
+    this->OldDir.clear();
+  }
+}
diff --git a/Source/cmWorkingDirectory.h b/Source/cmWorkingDirectory.h
new file mode 100644
index 0000000000000000000000000000000000000000..af0fd447dd5d120aeb57fb3bcdd468ce474dd567
--- /dev/null
+++ b/Source/cmWorkingDirectory.h
@@ -0,0 +1,25 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#ifndef cmWorkingDirectory_h
+#define cmWorkingDirectory_h
+
+#include <cmConfigure.h> // IWYU pragma: keep
+
+#include <string>
+
+/** \class cmWorkingDirectory
+ * \brief An RAII class to manipulate the working directory.
+ */
+class cmWorkingDirectory
+{
+public:
+  cmWorkingDirectory(std::string const& newdir);
+  ~cmWorkingDirectory();
+
+  void Pop();
+
+private:
+  std::string OldDir;
+};
+
+#endif
diff --git a/bootstrap b/bootstrap
index 8063edb19bf7415ef15c4b42447d19f313bcfd62..4f5836537d8523e8fe35e5fb2384b6bc3f46c76a 100755
--- a/bootstrap
+++ b/bootstrap
@@ -404,6 +404,7 @@ CMAKE_CXX_SOURCES="\
   cmUnsetCommand \
   cmVersion \
   cmWhileCommand \
+  cmWorkingDirectory \
   cmake  \
   cmakemain \
   cmcmd  \