diff --git a/README.md b/README.md index a249304..ff732b9 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,104 @@ -# winapps -Run Windows apps such as Microsoft Office in Linux (Ubuntu) and GNOME as if they were a part of the native OS. +# WinApps for Linux +Run Windows apps such as Microsoft Office in Linux (Ubuntu) and GNOME as if they were a part of the native OS, including Nautilus integration for right clicking on files of specific mime types to open them. + +![Demo](demo/demo.gif | width=600) + +## How it works and why WinApps exists +Back in April, Hayden Barnes [tweeted](https://twitter.com/unixterminal/status/1255919797692440578?lang=en) what appeared to be native Windows apps in a container or VM inside Ubuntu. However, no details have emerged on how this was accomplished, though it is likely a similar method to this but with an insider build Windows Container. + +Rather than wait around for this, WinApps was created as an easy, one command way to include apps running inside a VM (or on any RDP server) directly into GNOME as if they were native applications. WinApps works by: +- Running a Windows RDP server in a background VM container +- Checking the RDP server for installed applications such as Microsoft Office +- If those programs are installed, it creates shortcuts leveraging FreeRDP for both the CLI and the GNOME tray + +## Installation + +### Creating your WinApps configuration file +You will need to create a `~/.winapps` configuration file with the following information in it: +``` bash +RDP_USER="MyWindowsUser" +RDP_PASS="MyWindowsPassword" +#RDP_IP="192.168.123.111" +``` +If you are using Option 2 below with a pre-existing non-KVM RDP server, you can use the `RDP_IP` to specify it's location. If you are running a VM in KVM with NAT enabled, leave `RDP_IP` commented out and WinApps will auto-detect the right local IP. + +### Option 1 - Running KVM +You can refer to the [KVM](https://www.linux-kvm.org) documentation for specifics, but the first thing you need to do is set up a Virtual Machine running Windows 10 Professional (or any version that supports RDP). Fist, install KVM: +``` bash +git clone https://github.com/Fmstrat/winapps.git +cd winapps +sudo apt-get install -y virt-manager +``` + +Now set up KVM to run as your user instead of root and allow it through AppArmor (for Ubuntu 20.04 and above): +``` bash +sudo sed -i "s/#user = "root"/user = "$(id -un)"/g" /etc/libvirt/qemu.conf +sudo sed -i "s/#group = "root"/group = "$(id -gn)"/g" /etc/libvirt/qemu.conf +sudo usermod -a -G kvm $(id -un) +sudo usermod -a -G libvirt $(id -un) +sudo systemctl restart libvirtd +sudo ln -s /etc/apparmor.d/usr.sbin.libvirtd /etc/apparmor.d/disable/ + +sleep 5 + +sudo virsh net-autostart default +sudo virsh net-start default +``` +**You will likely need to reboot to ensure your current shell is added to the group.** + +Next, define a VM called RDPWindows from the sample XML file with: +``` bash +virsh define kvm/RDPWindows.xml +virsh autostart RDPWindows +``` + +You will now want to change any settings on the VM and install Windows. You can access the VM with: +``` bash +virt-manager +``` + +After the install process, you will want to: +- Go to the Start Menu + - Type "About" + - Open "About" + - Change the PC name to "RDPWindows" (This will allow WinApps to detect the local IP) +- Go to Control Panel + - Under "System," allow remote connections for RDP +- Merge `kvm/RDPApps.reg` into the registry to enable RDP Applications + +And the final step is to run the installer: +``` bash +$ ./install.sh +[sudo] password for fmstrat: +Installing... + Checking for installed apps in RDP machine... + Installing Excel... + Installing PowerPoint... + Installing Word... + Installing Windows... +Installation complete. +``` + +### Option 2 - I already have an RDP server or VM +If you already have an RDP server or VM, using WinApps is very straight forward. Simply create your `~/.winapps` configuration file, and run: +``` bash +$ git clone https://github.com/Fmstrat/winapps.git +$ cd winapps +$ ./install.sh +[sudo] password for fmstrat: +Installing... + Checking for installed apps in RDP machine... + Installing Excel... + Installing PowerPoint... + Installing Word... + Installing Windows... +Installation complete. +``` +You will need to make sure RDP Applications are enabled, which can be set by merging in `kvm/RDPApps.reg` into the registry. + +## Adding applications +Adding applications to the installer is easy. Simply copy one of the application configurations in the `apps` folder, and: +- Edit the variables for the application +- Replace the `icon.svg` with an SVG for the application +- Re-run the installer +- Submit a Pull Request to add it to WinApps officially \ No newline at end of file diff --git a/apps/excel/icon.svg b/apps/excel/icon.svg new file mode 100644 index 0000000..60f0f9c --- /dev/null +++ b/apps/excel/icon.svg @@ -0,0 +1 @@ +Excel_24x \ No newline at end of file diff --git a/apps/excel/info b/apps/excel/info new file mode 100644 index 0000000..2911fe5 --- /dev/null +++ b/apps/excel/info @@ -0,0 +1,17 @@ +# GNOME shortcut name +NAME="Excel" + +# Used for descriptions and window class +FULL_NAME="Microsoft Excel" + +# The executable inside windows +WIN_EXECUTABLE="C:\Program Files\Microsoft Office\Office16\EXCEL.EXE" + +# The icon in the icon folder +ICON="excel.svg" + +# GNOME categories +CATEGORIES="Office" + +# GNOME mimetypes +MIME_TYPES="application/vnd.ms-excel;application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;application/vnd.openxmlformats-officedocument.spreadsheetml.template;application/vnd.ms-excel.sheet.macroEnabled.12;application/vnd.ms-excel.template.macroEnabled.12;application/vnd.ms-excel.addin.macroEnabled.12;application/vnd.ms-excel.sheet.binary.macroEnabled.12;" diff --git a/apps/powerpoint/icon.svg b/apps/powerpoint/icon.svg new file mode 100644 index 0000000..7805223 --- /dev/null +++ b/apps/powerpoint/icon.svg @@ -0,0 +1 @@ +Powerpoint_24x \ No newline at end of file diff --git a/apps/powerpoint/info b/apps/powerpoint/info new file mode 100644 index 0000000..b2e506c --- /dev/null +++ b/apps/powerpoint/info @@ -0,0 +1,17 @@ +# GNOME shortcut name +NAME="PowerPoint" + +# Used for descriptions and window class +FULL_NAME="Microsoft PowerPoint" + +# The executable inside windows +WIN_EXECUTABLE="C:\Program Files\Microsoft Office\Office16\POWERPNT.EXE" + +# The icon in the icon folder +ICON="powerpoint.svg" + +# GNOME categories +CATEGORIES="Office" + +# GNOME mimetypes +MIME_TYPES="application/vnd.ms-powerpoint;application/vnd.openxmlformats-officedocument.presentationml.presentation;application/vnd.openxmlformats-officedocument.presentationml.template;application/vnd.openxmlformats-officedocument.presentationml.slideshow;application/vnd.ms-powerpoint.addin.macroEnabled.12;application/vnd.ms-powerpoint.presentation.macroEnabled.12;application/vnd.ms-powerpoint.template.macroEnabled.12;application/vnd.ms-powerpoint.slideshow.macroEnabled.12;" diff --git a/apps/word/icon.svg b/apps/word/icon.svg new file mode 100644 index 0000000..8018681 --- /dev/null +++ b/apps/word/icon.svg @@ -0,0 +1 @@ +Word_24x \ No newline at end of file diff --git a/apps/word/info b/apps/word/info new file mode 100644 index 0000000..22810ab --- /dev/null +++ b/apps/word/info @@ -0,0 +1,17 @@ +# GNOME shortcut name +NAME="Word" + +# Used for descriptions and window class +FULL_NAME="Microsoft Word" + +# The executable inside windows +WIN_EXECUTABLE="C:\Program Files\Microsoft Office\Office16\WINWORD.EXE" + +# The icon in the icon folder +ICON="word.svg" + +# GNOME categories +CATEGORIES="Office" + +# GNOME mimetypes +MIME_TYPES="application/msword;application/vnd.openxmlformats-officedocument.wordprocessingml.document;application/vnd.openxmlformats-officedocument.wordprocessingml.template;application/vnd.ms-word.document.macroEnabled.12;application/vnd.ms-word.template.macroEnabled.12;" diff --git a/bin/winapps b/bin/winapps new file mode 100755 index 0000000..c486112 --- /dev/null +++ b/bin/winapps @@ -0,0 +1,72 @@ +#!/usr/bin/env bash + +# Install windows in KVM +# Use the user "User" +# Name the machine "RDPWindows" in "About" +# Allow remote desktop +# +# virsh autostart RDPWindows +# For 20.04: +# sudo ln -s /etc/apparmor.d/usr.sbin.libvirtd /etc/apparmor.d/disable/ + +# Windows Registry Editor Version 5.00 + +# [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Terminal Server\TSAppAllowList] +# "fDisabledAllowList"=dword:00000001 + +# [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa] +# "LimitBlankPasswordUse"=dword:00000000 + +DIR="$(dirname "$(readlink -f "$0")")" + +if [ -f /tmp/winapps ]; then + LAST_RAN=$(stat -t -c %Y /tmp/winapps) + touch /tmp/winapps + THIS_RUN=$(stat -t -c %Y /tmp/winapps) + if (( $THIS_RUN - $LAST_RAN < 2 )); then + exit + fi +else + touch /tmp/winapps +fi + +if [ -z "$(which xfreerdp)" ]; then + echo "You need xfreerdp!" + echo " sudo apt-get install -y freerdp2-x11" + exit +fi + +if [ ! -f "${HOME}/.winapps" ]; then + echo "You need to create a ~/.winapps configuration. Exiting..." + exit +fi + +. "${HOME}/.winapps" + +if [ -z "${RDP_IP}" ]; then + if [ -z "$(groups |grep libvirt)" ]; then + echo "You are not a member of the libvirt group. Run the below then reboot." + echo ' sudo usermod -a -G libvirt $(whoami)' + echo ' sudo usermod -a -G kvm $(whoami)' + exit + fi + if [ -z "$(virsh list |grep RDPWindows)" ]; then + echo "RDPWindows is not running, run:" + echo " virsh start RDPWindows" + exit + fi + RDP_IP=$(virsh net-dhcp-leases default |grep RDPWindows |awk '{print $5}') + RDP_IP=${RDP_IP%%\/*} +fi + +if [ "${1}" = "windows" ]; then + xfreerdp /u:"${RDP_USER}" /p:"${RDP_PASS}" /v:${RDP_IP} /dynamic-resolution +auto-reconnect +home-drive /wm-class:"Microsoft Windows" 1> /dev/null 2>&1 & +elif [ "${1}" != "install" ]; then + . "${DIR}/../apps/${1}/info" + if [ -n "${2}" ]; then + FILE=$(echo "${2}" | sed 's|'"${HOME}"'|\\\\tsclient\\home|;s|/|\\|g;s|\\|\\\\|g') + xfreerdp /u:"${RDP_USER}" /p:"${RDP_PASS}" /v:${RDP_IP} +auto-reconnect +home-drive -wallpaper /span /wm-class:"${FULL_NAME}" /app:"${WIN_EXECUTABLE}" /app-icon:"${DIR}/../apps/${1}/icon.svg" /app-cmd:"\"${FILE}\"" 1> /dev/null 2>&1 & + else + xfreerdp /u:"${RDP_USER}" /p:"${RDP_PASS}" /v:${RDP_IP} +auto-reconnect +home-drive -wallpaper /span /wm-class:"${FULL_NAME}" /app:"${WIN_EXECUTABLE}" /app-icon:"${DIR}/../apps/${1}/icon.svg" 1> /dev/null 2>&1 & + fi +fi \ No newline at end of file diff --git a/demo/demo.gif b/demo/demo.gif new file mode 100644 index 0000000..a27d6f5 Binary files /dev/null and b/demo/demo.gif differ diff --git a/icons/onenote.svg b/icons/onenote.svg new file mode 100644 index 0000000..dc3615a --- /dev/null +++ b/icons/onenote.svg @@ -0,0 +1 @@ +OneNote_24x \ No newline at end of file diff --git a/icons/outlook.svg b/icons/outlook.svg new file mode 100644 index 0000000..6952781 --- /dev/null +++ b/icons/outlook.svg @@ -0,0 +1 @@ +Outlook_24x \ No newline at end of file diff --git a/icons/windows.svg b/icons/windows.svg new file mode 100644 index 0000000..793acfc --- /dev/null +++ b/icons/windows.svg @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/install.sh b/install.sh new file mode 100755 index 0000000..b13d291 --- /dev/null +++ b/install.sh @@ -0,0 +1,76 @@ +#!/usr/bin/env bash + +sudo ls > /dev/null + +echo "Installing..." + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" +. "${DIR}/bin/winapps" install + +# Check for installed apps +echo -n " Checking for installed apps in RDP machine..." +rm -f ${HOME}/.winapps.installed.bat +rm -f ${HOME}/.winapps.installed +for F in $(ls "${DIR}/apps"); do + . "${DIR}/apps/${F}/info" + echo "IF EXIST \"${WIN_EXECUTABLE}\" ECHO ${F} >> \\\\tsclient\\home\\.winapps.installed" >> ${HOME}/.winapps.installed.bat +done; +touch ${HOME}/.winapps.installed +LAST_RAN=$(stat -t -c %Y ${HOME}/.winapps.installed) +sleep 6 +xfreerdp /u:"${RDP_USER}" /p:"${RDP_PASS}" /v:${RDP_IP} +auto-reconnect +home-drive -wallpaper /span /wm-class:"RDPInstaller" /app:"C:\Windows\System32\cmd.exe" /app-icon:"${DIR}/../icons/windows.svg" /app-cmd:"/C \\\\tsclient\\home\\.winapps.installed.bat" 1> /dev/null 2>&1 & +sleep 6 +THIS_RUN=$(stat -t -c %Y ${HOME}/.winapps.installed) +while (( $THIS_RUN - $LAST_RAN < 5 )); do + sleep 5 + THIS_RUN=$(stat -t -c %Y ${HOME}/.winapps.installed) +done +echo "" + +# Install apps +for F in $(cat "${HOME}/.winapps.installed" |sed 's/\r/\n/g'); do + . "${DIR}/apps/${F}/info" + echo -n " Installing ${NAME}..." + sudo rm -f "/usr/share/applications/${F}.desktop" + echo "[Desktop Entry] +Name=${NAME} +Exec=${DIR}/bin/winapps ${F} %F +Terminal=false +Type=Application +Icon=${DIR}/apps/${F}/icon.svg +StartupWMClass=${FULL_NAME} +Comment=${FULL_NAME} +Categories=${CATEGORIES} +MimeType=${MIME_TYPES} +" |sudo tee "/usr/share/applications/${F}.desktop" > /dev/null + sudo rm -f "/usr/local/bin/${F}" + echo "#!/usr/bin/env bash +${DIR}/bin/winapps ${F} $@ +" |sudo tee "/usr/local/bin/${F}" > /dev/null + sudo chmod a+x "/usr/local/bin/${F}" + echo "" +done +rm -f "${HOME}/.winapps.installed" +rm -f "${HOME}/.winapps.installed.bat" + +# Install windows +echo -n " Installing Windows..." +sudo rm -f "/usr/share/applications/windows.desktop" +echo "[Desktop Entry] +Name=Windows +Exec=${DIR}/bin/winapps windows %F +Terminal=false +Type=Application +Icon=${DIR}/icons/windows.svg +StartupWMClass=Micorosoft Windows +Comment=Micorosoft Windows +Categories=Windows +" |sudo tee "/usr/share/applications/windows.desktop" > /dev/null +sudo rm -f "/usr/local/bin/windows" +echo "#!/usr/bin/env bash +${DIR}/bin/winapps windows +" |sudo tee "/usr/local/bin/windows" > /dev/null +sudo chmod a+x "/usr/local/bin/windows" +echo "" + +echo "Installation complete." \ No newline at end of file diff --git a/kvm/RDPApps.reg b/kvm/RDPApps.reg new file mode 100644 index 0000000..d8a3495 --- /dev/null +++ b/kvm/RDPApps.reg @@ -0,0 +1,4 @@ +Windows Registry Editor Version 5.00 + + [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Terminal Server\TSAppAllowList] + "fDisabledAllowList"=dword:00000001 diff --git a/kvm/RDPWindows.qcow2 b/kvm/RDPWindows.qcow2 new file mode 100644 index 0000000..71211c5 Binary files /dev/null and b/kvm/RDPWindows.qcow2 differ diff --git a/kvm/RDPWindows.xml b/kvm/RDPWindows.xml new file mode 100644 index 0000000..5427581 --- /dev/null +++ b/kvm/RDPWindows.xml @@ -0,0 +1,173 @@ + + RDPWindows + ad4c4f80-e908-4b25-afe8-1e915edabf26 + 4194304 + 4194304 + 2 + + /machine + + + hvm + + + + + + + + + + + + + + Haswell-noTSX-IBRS + Intel + + + + + + + + + + + + + + + + + + + + + + + + + + + destroy + restart + destroy + + + + + + /usr/bin/kvm-spice + + + + + + +
+ + + + + + +
+ + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + + + +
+ + + +
+ + + + + + + +
+ + + + + + + + + + + + + + + + +
+ + + +
+ + + + + + + + + + + + + +
+ +