private PatchScript runInstallPatch(DatabaseConnection pDatabaseConnection, String pPromoteUserName, String pPatchName) 
  throws ExInstaller {
    
    String lInstallPatchString;
    String lFileHash;
    try {
      lInstallPatchString = IOUtils.toString(getClass().getResourceAsStream(pPatchName));
      lFileHash = HashUtil.hashString(lInstallPatchString);
    }
    catch (IOException e) {
      throw new ExInstaller("Failed to read install patch script", e);
    }
    
    lInstallPatchString = lInstallPatchString.replaceAll(PROMOTE_USER_BIND_STRING, pPromoteUserName);
    lInstallPatchString = lInstallPatchString.replaceAll(INSTALL_LABEL_BIND_STRING, INSTALL_PROMOTION_LABEL);
        
    PatchScript lInstallPatchScript;
    try {
      lInstallPatchScript = PatchScript.createFromString(INSTALL_PATCH_NAME, lInstallPatchString, lFileHash, ScriptRunnerVersion.getVersionString());
    }
    catch (ExParser e) {
      throw new ExInstaller("Failed to parse install file as a PatchScript", e);
    }
    
    PatchScriptLoader lPatchScriptLoader = new PatchScriptLoader();
    try {
      lPatchScriptLoader.forceUnloggedRunPatchScript(pDatabaseConnection, lInstallPatchScript);
    }
    catch (ExPromote e) {
      throw new ExInstaller("Failed to install ScriptRunner: " + e.getMessage(), e);
    }
    
    return lInstallPatchScript;
  }