docs: @RequirePOST
      public void doDoInstall(StaplerRequest req, StaplerResponse rsp, @QueryParameter("dir") String _dir) throws IOException, ServletException {
          Jenkins.getInstance().checkPermission(Jenkins.ADMINISTER);
  
          if(installationDir!=null) {
              // installation already complete
              sendError("Installation is already complete",req,rsp);
              return;
          }
          if(!DotNet.isInstalled(2,0)) {
              sendError(".NET Framework 2.0 or later is required for this feature",req,rsp);
              return;
          }
  
          File dir = new File(_dir).getAbsoluteFile();
          dir.mkdirs();
          if(!dir.exists()) {
              sendError("Failed to create installation directory: "+dir,req,rsp);
              return;
          }
  
          try {
              // copy files over there
              copy(req, rsp, dir, getClass().getResource("/windows-service/jenkins.exe"),         "jenkins.exe");
              copy(req, rsp, dir, getClass().getResource("/windows-service/jenkins.exe.config"),  "jenkins.exe.config");
              copy(req, rsp, dir, getClass().getResource("/windows-service/jenkins.xml"),         "jenkins.xml");
              if(!hudsonWar.getCanonicalFile().equals(new File(dir,"jenkins.war").getCanonicalFile()))
                  copy(req, rsp, dir, hudsonWar.toURI().toURL(), "jenkins.war");
  
              // install as a service
              ByteArrayOutputStream baos = new ByteArrayOutputStream();
              StreamTaskListener task = new StreamTaskListener(baos);
              task.getLogger().println("Installing a service");
              int r = runElevated(new File(dir, "jenkins.exe"), "install", task, dir);
              if(r!=0) {
                  sendError(baos.toString(),req,rsp);
                  return;
              }
  
              // installation was successful
              installationDir = dir;
              rsp.sendRedirect(".");
          } catch (AbortException e) {
              // this exception is used as a signal to terminate processing. the error should have been already reported
          } catch (InterruptedException e) {
              throw new ServletException(e);
          }
      }