diff --git a/bin/pulsar-admin-common.cmd b/bin/pulsar-admin-common.cmd
new file mode 100644
index 0000000000000..b518734fa0bc8
--- /dev/null
+++ b/bin/pulsar-admin-common.cmd
@@ -0,0 +1,82 @@
+@REM
+@REM Licensed to the Apache Software Foundation (ASF) under one
+@REM or more contributor license agreements. See the NOTICE file
+@REM distributed with this work for additional information
+@REM regarding copyright ownership. The ASF licenses this file
+@REM to you under the Apache License, Version 2.0 (the
+@REM "License"); you may not use this file except in compliance
+@REM with the License. You may obtain a copy of the License at
+@REM
+@REM http://www.apache.org/licenses/LICENSE-2.0
+@REM
+@REM Unless required by applicable law or agreed to in writing,
+@REM software distributed under the License is distributed on an
+@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+@REM KIND, either express or implied. See the License for the
+@REM specific language governing permissions and limitations
+@REM under the License.
+@REM
+
+@echo off
+
+if "%JAVA_HOME%" == "" (
+ for %%i in (java.exe) do set "JAVACMD=%%~$PATH:i"
+) else (
+ set "JAVACMD=%JAVA_HOME%\bin\java.exe"
+)
+
+if not exist "%JAVACMD%" (
+ echo The JAVA_HOME environment variable is not defined correctly, so Pulsar CLI cannot be started. >&2
+ echo JAVA_HOME is set to "%JAVA_HOME%", but "%JAVACMD%" does not exist. >&2
+ goto error
+)
+
+
+for %%i in ("%~dp0.") do SET "SCRIPT_PATH=%%~fi"
+set "PULSAR_HOME_DIR=%SCRIPT_PATH%\..\"
+for %%i in ("%PULSAR_HOME_DIR%.") do SET "PULSAR_HOME=%%~fi"
+set "PULSAR_CLASSPATH=%PULSAR_CLASSPATH%;%PULSAR_HOME%\lib\*"
+
+
+if "%PULSAR_CLIENT_CONF%" == "" set "PULSAR_CLIENT_CONF=%PULSAR_HOME%\conf\client.conf"
+if "%PULSAR_LOG_CONF%" == "" set "PULSAR_LOG_CONF=%PULSAR_HOME%\conf\log4j2.yaml"
+
+set "PULSAR_LOG_CONF_DIR1=%PULSAR_LOG_CONF%\..\"
+for %%i in ("%PULSAR_LOG_CONF_DIR1%.") do SET "PULSAR_LOG_CONF_DIR=%%~fi"
+for %%a in ("%PULSAR_LOG_CONF%") do SET "PULSAR_LOG_CONF_BASENAME=%%~nxa"
+
+set "PULSAR_CLASSPATH=%PULSAR_CLASSPATH%;%PULSAR_LOG_CONF_DIR%"
+
+set "OPTS=%OPTS% -Dlog4j.configurationFile="%PULSAR_LOG_CONF_BASENAME%""
+set "OPTS=%OPTS% -Djava.net.preferIPv4Stack=true"
+
+set "isjava8=false"
+FOR /F "tokens=*" %%g IN ('"java -version 2>&1"') do (
+ echo %%g|find "version" >nul
+ if errorlevel 0 (
+ echo %%g|find "1.8" >nul
+ if errorlevel 0 (
+ set "isjava8=true"
+ )
+ )
+)
+
+if "%isjava8%" == "false" set "OPTS=%OPTS% --add-opens java.base/sun.net=ALL-UNNAMED"
+
+set "OPTS=-cp "%PULSAR_CLASSPATH%" %OPTS%"
+set "OPTS=%OPTS% %PULSAR_EXTRA_OPTS%"
+
+if "%PULSAR_LOG_DIR%" == "" set "PULSAR_LOG_DIR=%PULSAR_HOME%\logs"
+if "%PULSAR_LOG_APPENDER%" == "" set "PULSAR_LOG_APPENDER=RoutingAppender"
+if "%PULSAR_LOG_LEVEL%" == "" set "PULSAR_LOG_LEVEL=info"
+if "%PULSAR_LOG_ROOT_LEVEL%" == "" set "PULSAR_LOG_ROOT_LEVEL=%PULSAR_LOG_LEVEL%"
+if "%PULSAR_ROUTING_APPENDER_DEFAULT%" == "" set "PULSAR_ROUTING_APPENDER_DEFAULT=Console"
+
+set "OPTS=%OPTS% -Dpulsar.log.appender=%PULSAR_LOG_APPENDER%"
+set "OPTS=%OPTS% -Dpulsar.log.dir=%PULSAR_LOG_DIR%"
+set "OPTS=%OPTS% -Dpulsar.log.level=%PULSAR_LOG_LEVEL%"
+set "OPTS=%OPTS% -Dpulsar.log.root.level=%PULSAR_LOG_ROOT_LEVEL%"
+set "OPTS=%OPTS% -Dpulsar.routing.appender.default=%PULSAR_ROUTING_APPENDER_DEFAULT%"
+
+:error
+exit /b 1
diff --git a/bin/pulsar-admin.cmd b/bin/pulsar-admin.cmd
new file mode 100644
index 0000000000000..45bd8d4541fed
--- /dev/null
+++ b/bin/pulsar-admin.cmd
@@ -0,0 +1,30 @@
+@REM
+@REM Licensed to the Apache Software Foundation (ASF) under one
+@REM or more contributor license agreements. See the NOTICE file
+@REM distributed with this work for additional information
+@REM regarding copyright ownership. The ASF licenses this file
+@REM to you under the Apache License, Version 2.0 (the
+@REM "License"); you may not use this file except in compliance
+@REM with the License. You may obtain a copy of the License at
+@REM
+@REM http://www.apache.org/licenses/LICENSE-2.0
+@REM
+@REM Unless required by applicable law or agreed to in writing,
+@REM software distributed under the License is distributed on an
+@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+@REM KIND, either express or implied. See the License for the
+@REM specific language governing permissions and limitations
+@REM under the License.
+@REM
+
+@echo off
+
+for %%i in ("%~dp0.") do SET "SCRIPT_PATH=%%~fi"
+set "PULSAR_HOME_DIR=%SCRIPT_PATH%\..\"
+for %%i in ("%PULSAR_HOME_DIR%.") do SET "PULSAR_HOME=%%~fi"
+call "%PULSAR_HOME%\bin\pulsar-admin-common.cmd"
+if ERRORLEVEL 1 (
+ exit /b 1
+)
+cd "%PULSAR_HOME%"
+"%JAVACMD%" %OPTS% org.apache.pulsar.admin.cli.PulsarAdminTool %PULSAR_CLIENT_CONF% %*
\ No newline at end of file
diff --git a/bin/pulsar-client.cmd b/bin/pulsar-client.cmd
new file mode 100644
index 0000000000000..9e3cef45a25a7
--- /dev/null
+++ b/bin/pulsar-client.cmd
@@ -0,0 +1,30 @@
+@REM
+@REM Licensed to the Apache Software Foundation (ASF) under one
+@REM or more contributor license agreements. See the NOTICE file
+@REM distributed with this work for additional information
+@REM regarding copyright ownership. The ASF licenses this file
+@REM to you under the Apache License, Version 2.0 (the
+@REM "License"); you may not use this file except in compliance
+@REM with the License. You may obtain a copy of the License at
+@REM
+@REM http://www.apache.org/licenses/LICENSE-2.0
+@REM
+@REM Unless required by applicable law or agreed to in writing,
+@REM software distributed under the License is distributed on an
+@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+@REM KIND, either express or implied. See the License for the
+@REM specific language governing permissions and limitations
+@REM under the License.
+@REM
+
+@echo off
+
+for %%i in ("%~dp0.") do SET "SCRIPT_PATH=%%~fi"
+set "PULSAR_HOME_DIR=%SCRIPT_PATH%\..\"
+for %%i in ("%PULSAR_HOME_DIR%.") do SET "PULSAR_HOME=%%~fi"
+call "%PULSAR_HOME%\bin\pulsar-admin-common.cmd"
+if ERRORLEVEL 1 (
+ exit /b 1
+)
+cd "%PULSAR_HOME%"
+"%JAVACMD%" %OPTS% org.apache.pulsar.client.cli.PulsarClientTool %PULSAR_CLIENT_CONF% %*
\ No newline at end of file
diff --git a/bin/pulsar-perf.cmd b/bin/pulsar-perf.cmd
new file mode 100644
index 0000000000000..1a6acfbf6de36
--- /dev/null
+++ b/bin/pulsar-perf.cmd
@@ -0,0 +1,164 @@
+@REM
+@REM Licensed to the Apache Software Foundation (ASF) under one
+@REM or more contributor license agreements. See the NOTICE file
+@REM distributed with this work for additional information
+@REM regarding copyright ownership. The ASF licenses this file
+@REM to you under the Apache License, Version 2.0 (the
+@REM "License"); you may not use this file except in compliance
+@REM with the License. You may obtain a copy of the License at
+@REM
+@REM http://www.apache.org/licenses/LICENSE-2.0
+@REM
+@REM Unless required by applicable law or agreed to in writing,
+@REM software distributed under the License is distributed on an
+@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+@REM KIND, either express or implied. See the License for the
+@REM specific language governing permissions and limitations
+@REM under the License.
+@REM
+
+@echo off
+
+if "%JAVA_HOME%" == "" (
+ for %%i in (java.exe) do set "JAVACMD=%%~$PATH:i"
+) else (
+ set "JAVACMD=%JAVA_HOME%\bin\java.exe"
+)
+
+if not exist "%JAVACMD%" (
+ echo The JAVA_HOME environment variable is not defined correctly, so Pulsar CLI cannot be started. >&2
+ echo JAVA_HOME is set to "%JAVA_HOME%", but "%JAVACMD%" does not exist. >&2
+ exit /B 1
+)
+
+for %%i in ("%~dp0.") do SET "SCRIPT_PATH=%%~fi"
+set "PULSAR_HOME_DIR=%SCRIPT_PATH%\..\"
+for %%i in ("%PULSAR_HOME_DIR%.") do SET "PULSAR_HOME=%%~fi"
+set "PULSAR_CLASSPATH=%PULSAR_CLASSPATH%;%PULSAR_HOME%\lib\*"
+
+
+if "%PULSAR_CLIENT_CONF%" == "" set "PULSAR_CLIENT_CONF=%PULSAR_HOME%\conf\client.conf"
+if "%PULSAR_LOG_CONF%" == "" set "PULSAR_LOG_CONF=%PULSAR_HOME%\conf\log4j2.yaml"
+
+set "PULSAR_LOG_CONF_DIR1=%PULSAR_LOG_CONF%\..\"
+for %%i in ("%PULSAR_LOG_CONF_DIR1%.") do SET "PULSAR_LOG_CONF_DIR=%%~fi"
+for %%a in ("%PULSAR_LOG_CONF%") do SET "PULSAR_LOG_CONF_BASENAME=%%~nxa"
+
+set "PULSAR_CLASSPATH=%PULSAR_CLASSPATH%;%PULSAR_LOG_CONF_DIR%"
+if not "%PULSAR_EXTRA_CLASSPATH%" == "" set "PULSAR_CLASSPATH=%PULSAR_CLASSPATH%;%PULSAR_EXTRA_CLASSPATH%"
+
+
+if "%PULSAR_PERFTEST_CONF%" == "" set "PULSAR_PERFTEST_CONF=%PULSAR_CLIENT_CONF%"
+
+
+set "OPTS=%OPTS% -Dlog4j.configurationFile="%PULSAR_LOG_CONF_BASENAME%""
+set "OPTS=%OPTS% -Djava.net.preferIPv4Stack=true"
+
+
+set "OPTS=-cp "%PULSAR_CLASSPATH%" %OPTS%"
+set "OPTS=%OPTS% %PULSAR_EXTRA_OPTS%"
+
+if "%PULSAR_LOG_DIR%" == "" set "PULSAR_LOG_DIR=%PULSAR_HOME%\logs"
+if "%PULSAR_LOG_FILE%" == "" set "PULSAR_LOG_FILE=pulsar-perftest.log"
+if "%PULSAR_LOG_APPENDER%" == "" set "PULSAR_LOG_APPENDER=Console"
+if "%PULSAR_LOG_LEVEL%" == "" set "PULSAR_LOG_LEVEL=info"
+if "%PULSAR_LOG_ROOT_LEVEL%" == "" set "PULSAR_LOG_ROOT_LEVEL=%PULSAR_LOG_LEVEL%"
+
+
+set "OPTS=%OPTS% -Dpulsar.log.appender=%PULSAR_LOG_APPENDER%"
+set "OPTS=%OPTS% -Dpulsar.log.dir=%PULSAR_LOG_DIR%"
+set "OPTS=%OPTS% -Dpulsar.log.level=%PULSAR_LOG_LEVEL%"
+set "OPTS=%OPTS% -Dpulsar.log.root.level=%PULSAR_LOG_ROOT_LEVEL%"
+
+set "COMMAND=%1"
+
+for /f "tokens=1,* delims= " %%a in ("%*") do set "_args=%%b"
+
+if "%COMMAND%" == "produce" (
+ call :execCmdWithConfigFile org.apache.pulsar.testclient.PerformanceProducer
+ exit /B %ERROR_CODE%
+)
+if "%COMMAND%" == "consume" (
+ call :execCmdWithConfigFile org.apache.pulsar.testclient.PerformanceConsumer
+ exit /B %ERROR_CODE%
+)
+if "%COMMAND%" == "transaction" (
+ call :execCmdWithConfigFile org.apache.pulsar.testclient.PerformanceTransaction
+ exit /B %ERROR_CODE%
+)
+if "%COMMAND%" == "read" (
+ call :execCmdWithConfigFile org.apache.pulsar.testclient.PerformanceReader
+ exit /B %ERROR_CODE%
+)
+if "%COMMAND%" == "monitor-brokers" (
+ call :execCmd org.apache.pulsar.testclient.BrokerMonitor
+ exit /B %ERROR_CODE%
+)
+if "%COMMAND%" == "simulation-client" (
+ call :execCmd org.apache.pulsar.testclient.LoadSimulationClient
+ exit /B %ERROR_CODE%
+)
+if "%COMMAND%" == "simulation-controller" (
+ call :execCmd org.apache.pulsar.testclient.LoadSimulationController
+ exit /B %ERROR_CODE%
+)
+if "%COMMAND%" == "websocket-producer" (
+ call :execCmd org.apache.pulsar.proxy.socket.client.PerformanceClient
+ exit /B %ERROR_CODE%
+)
+if "%COMMAND%" == "managed-ledger" (
+ call :execCmd org.apache.pulsar.testclient.ManagedLedgerWriter
+ exit /B %ERROR_CODE%
+)
+if "%COMMAND%" == "gen-doc" (
+ call :execCmd org.apache.pulsar.testclient.CmdGenerateDocumentation
+ exit /B %ERROR_CODE%
+)
+
+call :usage
+exit /B %ERROR_CODE%
+
+:execCmdWithConfigFile
+"%JAVACMD%" %OPTS% %1 --conf-file "%PULSAR_PERFTEST_CONF%" %_args%
+if ERRORLEVEL 1 (
+ call :error
+)
+goto :eof
+
+:execCmd
+"%JAVACMD%" %OPTS% %1 %_args%
+if ERRORLEVEL 1 (
+ call :error
+)
+goto :eof
+
+
+
+:error
+set ERROR_CODE=1
+goto :eof
+
+
+
+
+:usage
+echo Usage: pulsar-perf COMMAND
+echo where command is one of:
+echo produce Run a producer
+echo consume Run a consumer
+echo transaction Run a transaction repeatedly
+echo read Run a topic reader
+echo websocket-producer Run a websocket producer
+echo managed-ledger Write directly on managed-ledgers
+echo monitor-brokers Continuously receive broker data and/or load reports
+echo simulation-client Run a simulation server acting as a Pulsar client
+echo simulation-controller Run a simulation controller to give commands to servers
+echo gen-doc Generate documentation automatically.
+echo help This help message
+echo or command is the full name of a class with a defined main() method.
+echo Environment variables:
+echo PULSAR_LOG_CONF Log4j configuration file (default %PULSAR_HOME%\logs)
+echo PULSAR_CLIENT_CONF Configuration file for client (default: %PULSAR_HOME%\conf\client.conf)
+echo PULSAR_EXTRA_OPTS Extra options to be passed to the jvm
+echo PULSAR_EXTRA_CLASSPATH Add extra paths to the pulsar classpath
+goto error
diff --git a/bin/pulsar-shell.cmd b/bin/pulsar-shell.cmd
new file mode 100644
index 0000000000000..e8d0a59e4d9fd
--- /dev/null
+++ b/bin/pulsar-shell.cmd
@@ -0,0 +1,33 @@
+@REM
+@REM Licensed to the Apache Software Foundation (ASF) under one
+@REM or more contributor license agreements. See the NOTICE file
+@REM distributed with this work for additional information
+@REM regarding copyright ownership. The ASF licenses this file
+@REM to you under the Apache License, Version 2.0 (the
+@REM "License"); you may not use this file except in compliance
+@REM with the License. You may obtain a copy of the License at
+@REM
+@REM http://www.apache.org/licenses/LICENSE-2.0
+@REM
+@REM Unless required by applicable law or agreed to in writing,
+@REM software distributed under the License is distributed on an
+@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+@REM KIND, either express or implied. See the License for the
+@REM specific language governing permissions and limitations
+@REM under the License.
+@REM
+
+@echo off
+
+for %%i in ("%~dp0.") do SET "SCRIPT_PATH=%%~fi"
+set "PULSAR_HOME_DIR=%SCRIPT_PATH%\..\"
+for %%i in ("%PULSAR_HOME_DIR%.") do SET "PULSAR_HOME=%%~fi"
+call "%PULSAR_HOME%\bin\pulsar-admin-common.cmd"
+if ERRORLEVEL 1 (
+ exit /b 1
+)
+
+set "OPTS=%OPTS% -Dorg.jline.terminal.jansi=false"
+set "DEFAULT_CONFIG=-Dpulsar.shell.config.default="%PULSAR_CLIENT_CONF%""
+
+"%JAVACMD%" %OPTS% %DEFAULT_CONFIG% org.apache.pulsar.shell.PulsarShell %*
\ No newline at end of file
diff --git a/distribution/shell/src/assemble/shell.xml b/distribution/shell/src/assemble/shell.xml
index 20265a6e82219..af1f229c7f7b0 100644
--- a/distribution/shell/src/assemble/shell.xml
+++ b/distribution/shell/src/assemble/shell.xml
@@ -24,6 +24,7 @@
shell
tar.gz
+ zip
true
diff --git a/pulsar-client-tools/pom.xml b/pulsar-client-tools/pom.xml
index 87dd76b48d4b2..4f16d8ebf84b7 100644
--- a/pulsar-client-tools/pom.xml
+++ b/pulsar-client-tools/pom.xml
@@ -118,6 +118,11 @@
jline
${jline3.version}
+
+ net.java.dev.jna
+ jna
+ runtime
+
org.apache.commons
commons-text
diff --git a/pulsar-client-tools/src/main/java/org/apache/pulsar/shell/PulsarShell.java b/pulsar-client-tools/src/main/java/org/apache/pulsar/shell/PulsarShell.java
index 4195edaf1f209..cbc043fe0c7e1 100644
--- a/pulsar-client-tools/src/main/java/org/apache/pulsar/shell/PulsarShell.java
+++ b/pulsar-client-tools/src/main/java/org/apache/pulsar/shell/PulsarShell.java
@@ -216,7 +216,6 @@ public void reload(Properties properties) throws Exception {
}
public void run() throws Exception {
- System.setProperty("org.jline.terminal.dumb", "true");
final Terminal terminal = TerminalBuilder.builder().build();
run((providersMap) -> {
List completers = new ArrayList<>();