|
1 | | -# Windows App Installer MultiTool |
| 1 | +# Remote Desktop Client Migration Script |
2 | 2 |
|
3 | | -A PowerShell utility to detect and install the Windows 365 "Windows App" client, optionally set its auto-update registry key, and remove legacy "Remote Desktop" installs when present. This README documents the script behavior, parameters, examples, logs and troubleshooting. |
| 3 | +## Overview |
| 4 | +This PowerShell script automates the migration from the legacy Remote Desktop client to the new **Windows App** (formerly Windows 365). It handles the installation of Windows App from multiple sources and optionally uninstalls the old Remote Desktop client. |
| 5 | + |
| 6 | +**Version:** 1.0 |
| 7 | +**Copyright:** Microsoft Corporation. All rights reserved. Licensed under the MIT license. |
4 | 8 |
|
5 | 9 | ## What it does |
6 | | -- Detects whether the Windows App (`MicrosoftCorporationII.Windows365`) is installed. |
| 10 | +- Detects whether the Windows App (`MicrosoftCorporationII.Windows365`) is already installed |
7 | 11 | - Installs the Windows App from one of three sources: |
8 | 12 | - Microsoft Store (via winget id `9N1F85V9T8BN`) — `Store` (default) |
9 | 13 | - WinGet CDN package (`Microsoft.WindowsApp`) — `WinGet` |
10 | 14 | - Direct MSIX download (FWLINK) and `Add-AppxPackage` — `MSIX` |
11 | | -- Optionally writes `HKLM:\SOFTWARE\Microsoft\WindowsApp\DisableAutomaticUpdates` to control auto updates. |
12 | | -- Optionally uninstalls legacy "Remote Desktop" via registry/MSI or package uninstall methods. |
13 | | -- Writes logs to console and to the configured log file. |
14 | | - |
15 | | -## Files |
16 | | -- `Windows App Installer.ps1` — main script. |
17 | | -- Runtime logs: |
18 | | - - Default log: `%windir%\Temp\MultiTool.log` (can be changed with `-logpath`) |
19 | | - - Store install trace: `%windir%\Temp\WindowsAppStoreInstall.log` |
20 | | - - WinGet install trace: `%windir%\Temp\WindowsAppWinGetInstall.log` |
21 | | - |
22 | | -## Requirements |
23 | | -- Windows (modern Windows 10/11 recommended). |
24 | | -- PowerShell (script compatible with Windows PowerShell 5.1 and later). |
25 | | -- Administrative privileges to install packages and write to HKLM. |
26 | | -- Internet access for Store/WinGet/MSIX downloads. |
27 | | -- Winget and/or Microsoft Store available for corresponding install methods (use `MSIX` when Store is blocked). |
| 15 | +- Validates successful Windows App installation |
| 16 | +- Optionally uninstalls legacy "Remote Desktop" client using two fallback methods: |
| 17 | + - Primary: Registry-based MSI uninstall |
| 18 | + - Fallback: Package-based uninstall |
| 19 | +- Optionally configures automatic update behavior via registry key |
| 20 | +- Comprehensive logging to console and file |
| 21 | + |
| 22 | +## Prerequisites |
| 23 | +- Windows 10/11 operating system |
| 24 | +- PowerShell 5.1 or later |
| 25 | +- Administrator privileges (required for package installation and registry modifications) |
| 26 | +- Internet connectivity (for downloading Windows App) |
| 27 | +- WinGet (if using WinGet installation method) |
| 28 | +- Microsoft Store access (if using Store installation method, or use `MSIX` when Store is blocked) |
28 | 29 |
|
29 | 30 | ## Parameters |
30 | | -- `-source` (string) |
31 | | - Where to source the installer payload. Allowed values: `Store` (default), `WinGet`, `MSIX`. |
32 | | -- `-DisableAutoUpdate` (int) |
33 | | - Sets the registry DWORD `HKLM:\SOFTWARE\Microsoft\WindowsApp\DisableAutomaticUpdates`. Allowed values: |
34 | | - - `0` — Enable updates (default) |
35 | | - - `1` — Disable updates from all locations |
36 | | - - `2` — Disable updates from Microsoft Store |
37 | | - - `3` — Disable updates from the CDN |
38 | | -- `-SkipRemoteDesktopUninstall` (switch) |
39 | | - If present, skip attempting to remove legacy Remote Desktop. |
40 | | -- `-logpath` (string) |
41 | | - Path to the primary log file (default: `$env:windir\temp\MultiTool.log`). |
42 | | - |
43 | | -## High-level functions (what they do) |
44 | | -- `update-log` — logging helper (console / file / both). |
45 | | -- `invoke-WAInstallCheck` — returns 0 if Windows App is present, 1 otherwise. |
46 | | -- `install-windowsappstore` — triggers Store install (uses winget id `9N1F85V9T8BN`) and logs to temp file. |
47 | | -- `install-windowsappwinget` — triggers WinGet install for `Microsoft.WindowsApp` and logs to temp file. |
48 | | -- `install-windowsappMSIX` — downloads MSIX via FWLINK and installs with `Add-AppxPackage`. |
49 | | -- `uninstall-MSRDCreg` — primary uninstall of legacy Remote Desktop via registry MSI uninstall string. |
50 | | -- `uninstall-MSRDC` — secondary uninstall via `Get-Package` / `Uninstall-Package`. |
51 | | -- `invoke-disableautoupdate` — creates/sets `DisableAutomaticUpdates` DWORD. |
52 | | - |
53 | | -## Usage examples (run elevated) |
54 | | -Default (Store) install: |
| 31 | + |
| 32 | +### `-source` |
| 33 | +Specifies where to source the Windows App installer payload. |
| 34 | + |
| 35 | +**Type:** String |
| 36 | +**Valid Values:** `Store`, `WinGet`, `MSIX` |
| 37 | +**Default:** `Store` |
| 38 | +**Required:** No |
| 39 | + |
| 40 | +- `Store`: Installs from Microsoft Store (ID: 9N1F85V9T8BN) |
| 41 | +- `WinGet`: Installs from WinGet CDN using package ID `Microsoft.WindowsApp` |
| 42 | +- `MSIX`: Downloads and installs directly from MSIX package (use when Store is blocked) |
| 43 | + |
| 44 | +### `-DisableAutoUpdate` |
| 45 | +Controls the automatic update behavior for Windows App by setting the registry key `HKLM:\SOFTWARE\Microsoft\WindowsApp\DisableAutomaticUpdates`. |
| 46 | + |
| 47 | +**Type:** Integer |
| 48 | +**Valid Values:** `0`, `1`, `2`, `3` |
| 49 | +**Default:** `0` |
| 50 | +**Required:** No |
| 51 | + |
| 52 | +- `0`: Enables updates (default) |
| 53 | +- `1`: Disables updates from all locations |
| 54 | +- `2`: Disables updates from Microsoft Store only |
| 55 | +- `3`: Disables updates from CDN location only |
| 56 | + |
| 57 | +### `-SkipRemoteDesktopUninstall` |
| 58 | +Prevents the script from uninstalling the Remote Desktop client. |
| 59 | + |
| 60 | +**Type:** Switch |
| 61 | +**Default:** `$false` |
| 62 | +**Required:** No |
| 63 | + |
| 64 | +### `-logpath` |
| 65 | +Specifies the location and filename for the script log. |
| 66 | + |
| 67 | +**Type:** String |
| 68 | +**Default:** `$env:windir\temp\RDC-Migration.log` |
| 69 | +**Required:** No |
| 70 | + |
| 71 | +## Usage Examples |
| 72 | + |
| 73 | +### Basic Usage (Microsoft Store - Default) |
| 74 | +```powershell |
| 75 | +.\Remote Desktop Client Migration Script.ps1 |
| 76 | +``` |
| 77 | + |
| 78 | +### Install from WinGet |
| 79 | +```powershell |
| 80 | +.\Remote Desktop Client Migration Script.ps1 -source WinGet |
| 81 | +``` |
| 82 | + |
| 83 | +### Install from MSIX (Direct Download) |
| 84 | +```powershell |
| 85 | +.\Remote Desktop Client Migration Script.ps1 -source MSIX |
| 86 | +``` |
| 87 | + |
| 88 | +### Disable All Auto-Updates |
| 89 | +```powershell |
| 90 | +.\Remote Desktop Client Migration Script.ps1 -DisableAutoUpdate 1 |
| 91 | +``` |
| 92 | + |
| 93 | +### Disable Store Updates Only |
| 94 | +```powershell |
| 95 | +.\Remote Desktop Client Migration Script.ps1 -source WinGet -DisableAutoUpdate 2 |
| 96 | +``` |
| 97 | + |
| 98 | +### Keep Remote Desktop Client Installed |
55 | 99 | ```powershell |
56 | | -PowerShell -ExecutionPolicy Bypass -File ".\Windows App Installer.ps1" |
| 100 | +.\Remote Desktop Client Migration Script.ps1 -SkipRemoteDesktopUninstall |
57 | 101 | ``` |
58 | 102 |
|
59 | | -Install via WinGet and disable Store updates (set key = 2): |
| 103 | +### Custom Log Location |
60 | 104 | ```powershell |
61 | | -PowerShell -ExecutionPolicy Bypass -File ".\Windows App Installer.ps1" -source WinGet -DisableAutoUpdate 2 |
| 105 | +.\Remote Desktop Client Migration Script.ps1 -logpath "C:\Logs\RDC-Migration.log" |
62 | 106 | ``` |
63 | 107 |
|
64 | | -Install via MSIX and skip removing legacy Remote Desktop: |
| 108 | +### Full Example with All Parameters |
65 | 109 | ```powershell |
66 | | -PowerShell -ExecutionPolicy Bypass -File ".\Windows App Installer.ps1" -source MSIX -SkipRemoteDesktopUninstall |
| 110 | +.\Remote Desktop Client Migration Script.ps1 -source Store -DisableAutoUpdate 2 -logpath "C:\Logs\migration.log" |
67 | 111 | ``` |
68 | 112 |
|
69 | | -Specify an alternate log file: |
| 113 | +### Run with Execution Policy Bypass |
70 | 114 | ```powershell |
71 | | -PowerShell -ExecutionPolicy Bypass -File ".\Windows App Installer.ps1" -logpath "C:\Temp\WinAppInstall.log" |
| 115 | +PowerShell -ExecutionPolicy Bypass -File ".\Remote Desktop Client Migration Script.ps1" -source MSIX -SkipRemoteDesktopUninstall |
72 | 116 | ``` |
73 | 117 |
|
74 | | -## Exit behavior & logs |
75 | | -- On fatal install failures the script calls `exit 1`. |
76 | | -- Normal success writes completion messages to logs and returns normally. |
77 | | -- Check logs for details: |
78 | | - - Primary: `%windir%\Temp\MultiTool.log` (or the `-logpath` you supplied) |
79 | | - - Install traces: `%windir%\Temp\WindowsAppStoreInstall.log`, `%windir%\Temp\WindowsAppWinGetInstall.log` |
| 118 | +## How It Works |
| 119 | + |
| 120 | +The script follows this workflow: |
| 121 | + |
| 122 | +1. **Pre-Installation Check**: Verifies if Windows App is already installed |
| 123 | + - If found, skips installation |
| 124 | + - If not found, proceeds to installation |
| 125 | + |
| 126 | +2. **Installation**: Installs Windows App from the specified source |
| 127 | + - **Store**: Uses WinGet with Store ID `9N1F85V9T8BN` |
| 128 | + - **WinGet**: Uses WinGet CDN package `Microsoft.WindowsApp` |
| 129 | + - **MSIX**: Downloads from `https://go.microsoft.com/fwlink/?linkid=2262633` and installs via `Add-AppxPackage` |
| 130 | + |
| 131 | +3. **Validation**: Confirms successful Windows App installation |
| 132 | + - Checks for AppX package `MicrosoftCorporationII.Windows365` |
| 133 | + - Exits with error code 1 if not found |
| 134 | + |
| 135 | +4. **Uninstallation** (unless `-SkipRemoteDesktopUninstall` is used): |
| 136 | + - **Primary Method**: Registry-based MSI uninstall using `MsiExec.exe /x` |
| 137 | + - **Fallback Method**: Package-based uninstall using `Uninstall-Package` |
| 138 | + |
| 139 | +5. **Configuration**: Applies auto-update registry settings if specified |
| 140 | + |
| 141 | +6. **Completion**: Logs final status and exits |
| 142 | + |
| 143 | +## Log Files |
| 144 | + |
| 145 | +### Main Script Log |
| 146 | +- **Default Location:** `%windir%\temp\RDC-Migration.log` |
| 147 | +- **Configurable via:** `-logpath` parameter |
| 148 | +- **Contains:** Detailed information about script execution with timestamps, actions, warnings, and errors |
| 149 | + |
| 150 | +### Installation Process Logs |
| 151 | +- **Store Installation:** `%windir%\temp\WindowsAppStoreInstall.log` |
| 152 | +- **WinGet Installation:** `%windir%\temp\WindowsAppWinGetInstall.log` |
| 153 | +- **MSIX Download:** Payload downloaded to `%windir%\temp\` |
| 154 | + |
| 155 | +### Log Format |
| 156 | +Each log entry includes: |
| 157 | +- Log level (Information, Warning, Error, Comment) |
| 158 | +- Timestamp in format: `MM/DD/YY HH:MM:SS AM/PM` |
| 159 | +- Descriptive message |
| 160 | + |
| 161 | +## Exit Codes |
| 162 | +- **0**: Success (normal completion) |
| 163 | +- **1**: Failure (Windows App installation failed or not detected after installation) |
| 164 | + |
| 165 | +## Script Functions |
| 166 | + |
| 167 | +The script includes the following key functions: |
| 168 | + |
| 169 | +- **`update-log`**: Logging helper that writes to console and/or file with timestamps |
| 170 | +- **`invoke-WAInstallCheck`**: Checks if Windows App is installed (returns 0 if present, 1 if not) |
| 171 | +- **`install-windowsappstore`**: Installs Windows App from Microsoft Store via WinGet |
| 172 | +- **`install-windowsappwinget`**: Installs Windows App from WinGet CDN |
| 173 | +- **`install-windowsappMSIX`**: Downloads and installs Windows App from direct MSIX download |
| 174 | +- **`uninstall-MSRDCreg`**: Primary method to uninstall Remote Desktop via registry MSI uninstall string |
| 175 | +- **`uninstall-MSRDC`**: Fallback method to uninstall Remote Desktop via `Get-Package`/`Uninstall-Package` |
| 176 | +- **`invoke-disableautoupdate`**: Creates/sets the `DisableAutomaticUpdates` registry key |
| 177 | + |
| 178 | +## Registry Configuration |
| 179 | + |
| 180 | +When using `-DisableAutoUpdate`, the script creates/modifies: |
| 181 | + |
| 182 | +``` |
| 183 | +Registry Key: HKLM:\SOFTWARE\Microsoft\WindowsApp |
| 184 | +Value Name: DisableAutomaticUpdates |
| 185 | +Value Type: DWORD |
| 186 | +``` |
80 | 187 |
|
81 | 188 | ## Troubleshooting |
82 | | -- Permission / access denied: |
83 | | - - Run PowerShell as Administrator. |
84 | | -- Winget not found or Microsoft Store disabled: |
85 | | - - Use `-source MSIX` to attempt a direct MSIX install. |
86 | | -- `Add-AppxPackage` errors: |
87 | | - - Ensure sideloading is allowed or that the package signature and system policy permit the install. |
88 | | -- Remote Desktop uninstall fails: |
89 | | - - The script tries registry/MSI first then package uninstall. Manual removal may be required if uninstall strings are missing. |
90 | | -- For diagnostics: |
91 | | - - Inspect the three logs listed above for error messages and stack traces. |
92 | | - |
93 | | -## Known limitations |
94 | | -- Script assumes availability of `winget` for Store/WinGet flows; environments with Store disabled may fail unless `MSIX` chosen. |
95 | | -- Error handling is present but could be more granular (some functions catch and log but do not standardize exit codes). |
96 | | -- Not explicitly tested on Windows LTSC or older Windows 10 branches — behavior may vary. |
97 | | - |
98 | | -## Recommended next steps |
99 | | -- Add a `-WhatIf`/dry-run mode. |
100 | | -- Add explicit checks for `winget`/Store presence before choosing install path. |
101 | | -- Convert `update-log` to structured logging (timestamped JSON) for automation. |
102 | | -- Add more granular exit codes to represent specific failure types. |
| 189 | + |
| 190 | +### Permission or Access Denied Errors |
| 191 | +- Ensure PowerShell is running as Administrator |
| 192 | +- Verify write permissions to log directory and registry |
| 193 | + |
| 194 | +### Windows App Installation Fails |
| 195 | +- **Check Internet Connectivity**: Ensure the device can reach Microsoft services |
| 196 | +- **WinGet Not Found**: If using Store or WinGet source, verify WinGet is installed |
| 197 | +- **Microsoft Store Disabled**: Use `-source MSIX` for direct MSIX installation |
| 198 | +- **Review Logs**: Check installation logs in `%windir%\temp\` for specific errors |
| 199 | + |
| 200 | +### AppX Package Installation Errors |
| 201 | +- Ensure sideloading is allowed in Windows settings |
| 202 | +- Verify package signature and system policy permit installation |
| 203 | +- Check if Developer Mode is required |
| 204 | + |
| 205 | +### Remote Desktop Uninstall Issues |
| 206 | +- The script automatically tries two methods (registry-based MSI and package-based) |
| 207 | +- Check the main log file for specific error messages |
| 208 | +- Use `-SkipRemoteDesktopUninstall` to bypass uninstallation if problematic |
| 209 | +- Manual removal may be required if uninstall strings are missing |
| 210 | + |
| 211 | +### Script Exits with Error Code 1 |
| 212 | +- Windows App installation failed or was not detected after installation |
| 213 | +- Review all log files for error details |
| 214 | +- Try an alternative installation source |
| 215 | + |
| 216 | +### WinGet Command Not Recognized |
| 217 | +- Install App Installer from Microsoft Store |
| 218 | +- Or use `-source MSIX` to bypass WinGet requirement |
| 219 | + |
| 220 | +## Known Limitations |
| 221 | +- Script assumes WinGet availability for Store/WinGet installation methods |
| 222 | +- Error handling logs exceptions but may not provide granular exit codes for all failure types |
| 223 | +- Not extensively tested on Windows LTSC or older Windows 10 branches |
| 224 | +- Requires internet connectivity for all installation sources |
| 225 | + |
| 226 | +## Additional Information |
| 227 | + |
| 228 | +For more information about this script and other Windows 365 PowerShell scripts, visit: |
| 229 | +**https://github.com/microsoft/Windows365-PSScripts** |
103 | 230 |
|
104 | 231 | ## License |
105 | | -No license is specified. Add a `LICENSE` file if you intend to publish or share. |
| 232 | +Copyright (c) Microsoft Corporation. All rights reserved. |
| 233 | +Licensed under the MIT license. See LICENSE in the project root for license information. |
0 commit comments