Update readme.

This commit is contained in:
Jared Goodwin 2024-07-09 13:46:10 -07:00
parent 6292ef99b4
commit 7881e0334f
2 changed files with 148 additions and 129 deletions

View File

@ -1,19 +1,18 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
title: ""
labels: ""
assignees: ""
---
<!--
Your bug must meet the following requirements, or else it will be closed. For issues that don't meet these requirements, please reach out to the community on the official subreddit (https://www.reddit.com/r/remotely_app/) or in the Discussion areas on GitHub.
Your bug must meet the following requirements, or else it will be closed. For issues that don't meet these requirements, please reach out to the community in the Discussion areas on GitHub.
Requirements:
- ⚠️ Please read the following section in the readme before continuing: https://github.com/immense/Remotely?tab=readme-ov-file#important-https-and-reverse-proxies⚠
- You are running Remotely in Docker using our official image
-
- The bug must be related specifically to application code (e.g. not related to hosting, reverse proxy configuration, etc.).
- It must be immediately reproducible, either in a debug environment or on https://app.remotely.one. (This doesn't apply to bugs that are clearly code-related.)
@ -25,6 +24,7 @@ A clear and concise description of what the bug is. Ideally with a screenshot if
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
@ -41,17 +41,17 @@ A clear and concise description of what you expected to happen.
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Smartphone (please complete the following information):**
- Device: [e.g. iPhone13]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]
- Device: [e.g. iPhone13]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]
**Additional Context**
Add any other context about the problem here.
- [ ] I am running Remotely in Docker and not on my QNAP, Synology, or Internet Connected Toaster

247
README.md
View File

@ -1,4 +1,5 @@
# Remotely
A remote control and remote scripting solution, built with .NET, Blazor, and SignalR Core.
[![Build Status](https://dev.azure.com/immybot/Remotely/_apis/build/status%2Fimmense.Remotely?branchName=master)](https://dev.azure.com/immybot/Remotely/_build/latest?definitionId=2&branchName=master)
@ -6,9 +7,10 @@ A remote control and remote scripting solution, built with .NET, Blazor, and Sig
## Looking for Maintainers
I'm looking for maintainers to help me out! If you are a .NET dev and are interested in helping to keep Remotely moving forward, send me a DM on Discord at `jaredatimmy`.
I'm looking for maintainers to help me out! If you are a .NET dev and are interested in helping to keep Remotely moving forward, send me a DM on Discord at `jaredatimmy`.
## Project Links
Subreddit: https://www.reddit.com/r/remotely_app/
Docker: https://hub.docker.com/r/immybot/remotely
Tutorial: https://www.youtube.com/watch?v=t-TFvr7sZ6M (Thanks, @bmcgonag!)
@ -16,6 +18,7 @@ Tutorial: https://www.youtube.com/watch?v=t-TFvr7sZ6M (Thanks, @bmcgonag!)
![image](.github/media/ask-remote.png)
## Quickstart
```
mkdir -p /var/www/remotely
wget -q https://raw.githubusercontent.com/immense/Remotely/master/docker-compose/docker-compose.yml
@ -23,20 +26,21 @@ docker-compose up -d
```
## Important: HTTPS and Reverse Proxies
The only supported reverse proxy is Caddy, and only when it is directly facing the internet. The default configuration for Caddy provides everything that ASP.NET Core and SignalR need to function correctly.
If you are having networking issues with any other setup, such as with an additional firewall or with Nginx, please seek out community support in the Discussions tab, on Reddit, or another social site. The Remotely maintainers simply can't provide guidance and support for all the possible environment setups.
The only supported reverse proxy is Caddy, and only when it is directly facing the internet. The default configuration for Caddy provides everything that ASP.NET Core and SignalR need to function correctly.
With that said, ASP.NET Core requires the following headers to be set when behind a reverse proxy: `X-Forwarded-Proto`, `X-Forwarded-Host`, and `X-Forwarded-For`. These correlate to the scheme (http/https), the URL of the original request, and the client's IP address, respectively. The resulting scheme and host are injected into the installers and desktop clients, so they know where to send requests. The client IP address is used in the device info.
If you are having networking issues with any other setup, such as with an additional firewall or with Nginx, please seek out community support in the Discussions tab, on Reddit, or another social site. The Remotely maintainers simply can't provide guidance and support for all the possible environment setups.
The Remotely code does not parse or handle these values. It is done internally by ASP.NET Core's built-in middleware. If the values are not appearing as expected, it is because the headers were missing, didn't contain the correct values, were not in the correct format, or didn't come through a chain of known proxies (see below).
With that said, Remotely requires the following headers to be set: `X-Forwarded-Proto`, `X-Forwarded-Host`, and `X-Forwarded-For`. These correlate to the scheme (http/https), the URL of the original request, and the client's IP address, respectively. The resulting scheme and host are injected into the installers and desktop clients, so they know where to send requests. The client IP address is used in the device info.
To avoid injection attacks, ASP.NET Core defaults to only accepting forwarded headers from loopback addresses. Remotely will also add the Docker gateway IP (172.28.0.1) defined in the docker-compose file. If you are using a non-default configuration, you must add all firewall and reverse proxy addresses to the `KnownProxies` array in the Server Config.
The Remotely code does not parse or handle these values. It is done internally by ASP.NET Core's built-in middleware. If the values are not appearing as expected, it is because the headers were missing, didn't contain the correct values, were not the correct format, or didn't come through a chain of known proxies (see below).
If you are unable to get your reverse proxies configured correctly, you can at least force the use of HTTPS scheme by setting `Force Client HTTPS` in the Server Config page.
To avoid injection attacks, ASP.NET Core defaults to only accepting forwarded headers from loopback addresses. Remotely will also add the default Docker host IP (172.17.0.1). If you are using a non-default configuration, you must add all firewall and reverse proxy addresses to the `KnownProxies` array in the Server Config.
Microsoft's full documentation on the topic can be found here: https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/proxy-load-balancer
## After Installation
- Data for Remotely will be saved in the container under `/app/AppData`, which will be mounted to `/var/www/remotely/` on your Docker host.
- This folder will contain Remotely.db and logs generated by the server.
- These files will persist through teardown and setup of new Remotely containers.
@ -51,54 +55,59 @@ If you are unable to get your reverse proxies configured correctly, you can at l
- People will no longer be able to create accounts on their own.
- To allow self-registration, increase the `MaxOrganizationCount` or set it to -1 (see Configuration section).
## HTTP Logging
You can enable HTTP logging to see all requests and responses in the server logs, including headers. This can be helpful for debugging reverse proxy, API, or SignalR issues. The option can be enabled on the Server Config page.
You can enable HTTP logging to see all requests and responses in the server logs, including headers. This can be helpful for debugging reverse proxy, API, or SignalR issues. The option can be enabled on the Server Config page.
After changing the above, you must restart the container for the changes to take effect.
## Build and Debug Instructions (Windows 11)
## Build and Debug Instructions (Windows 11)
The following steps will configure your Windows 11 machine for building the Remotely server and clients.
- Install Visual Studio 2022.
- Link: https://visualstudio.microsoft.com/downloads/
- You should have the following Workloads selected:
- ASP.NET and web development
- .NET desktop development
- .NET Core cross-platform development
- You should have the following Individual Components selected:
- .NET SDK (latest version).
- MSBuild (which auto-selects Roslyn compilers).
- NuGet targets and build tasks.
- .NET Framework 4.8 SDK.
- For debugging and development, you'll need all relevant workloads.
- Link: https://visualstudio.microsoft.com/downloads/
- You should have the following Workloads selected:
- ASP.NET and web development
- .NET desktop development
- .NET Core cross-platform development
- You should have the following Individual Components selected:
- .NET SDK (latest version).
- MSBuild (which auto-selects Roslyn compilers).
- NuGet targets and build tasks.
- .NET Framework 4.8 SDK.
- For debugging and development, you'll need all relevant workloads.
- Install Git for Windows.
- Link: https://git-scm.com/downloads
- Link: https://git-scm.com/downloads
- Install the latest LTS Node:
- Link: https://nodejs.org/
- Link: https://nodejs.org/
- Clone the git repository: `git clone https://github.com/immense/Remotely --recurse`
- When debugging, the agent will use a pre-defined device ID and connect to https://localhost:5001.
- In development environment, the server will assign all connecting agents to the first organization.
- The above two allow you to debug the agent and server together, and see your device in the list.
## Admin Accounts
The first account created will be an admin for both the server and the organization that's created for the account.
An organization admin has access to the Organization page and server log entries specific to his/her organization. A server admin has access to the Server Config page and can see server log entries that don't belong to an organization.
An organization admin has access to the Organization page and server log entries specific to his/her organization. A server admin has access to the Server Config page and can see server log entries that don't belong to an organization.
## Branding
Within the Account section, there is a tab for branding, which will apply to the quick support clients and Windows installer.
However, the clients will need to have been built from source with the server URL hard-coded in the apps for them to be able to retrieve the branding info.
## Configuration
The database provider, connection strings, and ASP.NET Core port are configurable via environment variables in `docker-compose.yml`.
All other configuration is done in the Server Config page once you're logged in.
- AllowApiLogin: Whether to allow logging in via the API controller. API access tokens are recommended over this approach.
- BannedDevices: An array of device IDs, names, or IP addresses to ban. When they try to connect, an uninstall command will immediately be sent back.
- DataRetentionInDays: How long logs and other data will be kept on the server. Set to -1 to retain indefinitely (not recommended).
- DBProvider: Determines which of the three connection strings (at the top) will be used. The appropriate DB provider for the database type is automatically loaded in code.
- AllowApiLogin: Whether to allow logging in via the API controller. API access tokens are recommended over this approach.
- BannedDevices: An array of device IDs, names, or IP addresses to ban. When they try to connect, an uninstall command will immediately be sent back.
- DataRetentionInDays: How long logs and other data will be kept on the server. Set to -1 to retain indefinitely (not recommended).
- DBProvider: Determines which of the three connection strings (at the top) will be used. The appropriate DB provider for the database type is automatically loaded in code.
- EnableWindowsEventLog: Whether to also add server log entries to the Windows Event Log.
- EnforceAttendedAccess: Clients will be prompted to allow unattended remote control attempts.
- EnableRemoteControlRecording: Whether to save recordings of remote control sessions on the server.
@ -106,147 +115,157 @@ All other configuration is done in the Server Config page once you're logged in.
- Their retention is governed by `DataRetentionInDays`.
- ForceClientHTTPS: Force installers and desktop clients to use HTTPS scheme, even if forwarded headers is misconfigured.
- KnownProxies: If your reverse proxy is on a different machine and is forwarding requests to the Remotely server, you will need to add the IP of the reverse proxy server to this array.
- MaxOrganizationCount: By default, one organization can exist on the server, which is created automatically when the first account is registered. Afterward, self-registration will be disabled.
- Set this to -1 or increase it to a specific number to allow multi-tenancy.
- RedirectToHttps: Whether ASP.NET Core will redirect all traffic from HTTP to HTTPS. This is independent of Caddy, Nginx, and IIS configurations that do the same.
- MaxOrganizationCount: By default, one organization can exist on the server, which is created automatically when the first account is registered. Afterward, self-registration will be disabled.
- Set this to -1 or increase it to a specific number to allow multi-tenancy.
- RedirectToHttps: Whether ASP.NET Core will redirect all traffic from HTTP to HTTPS. This is independent of Caddy, Nginx, and IIS configurations that do the same.
- RemoteControlNotifyUsers: Whether to show a notification to the end user when an unattended remote control session starts.
- RemoteControlSessionLimit: How many concurrent remote control sessions are allowed per organization.
- RemoteControlRequiresAuthentication: Whether the remote control page requires authentication to establish a connection.
- Require2FA: Require users to set up 2FA before they can use the main app.
- Smpt-: SMTP settings for auto-generated system emails (such as registration and password reset).
- Theme: The color theme to use for the site. Values are "Light" or "Dark". This can also be configured per-user in Account - Options.
- TrustedCorsOrigins: For cross-origin API requests via JavaScript. The websites listed in this array with be allowed to make requests to the API. This does not grant authentication, which is still required on most endpoints.
- Theme: The color theme to use for the site. Values are "Light" or "Dark". This can also be configured per-user in Account - Options.
- TrustedCorsOrigins: For cross-origin API requests via JavaScript. The websites listed in this array with be allowed to make requests to the API. This does not grant authentication, which is still required on most endpoints.
- UseHsts: Whether ASP.NET Core will use HTTP Strict Transport Security.
- UseHttpLogging: Enables logging for all HTTP requests. Also enables additional log entries in `ClientDownloadsController` regarding the effective scheme, host, and remote IP address as a result of processing forwarded headers.
- You must explicitly set a log level for `Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware` for this to work. See the [appsettings.json](https://github.com/immense/Remotely/blob/master/Server/appsettings.json) for an example.
- UseHttpLogging: Enables logging for all HTTP requests. Also enables additional log entries in `ClientDownloadsController` regarding the effective scheme, host, and remote IP address as a result of processing forwarded headers.
- You must explicitly set a log level for `Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware` for this to work. See the [appsettings.json](https://github.com/immense/Remotely/blob/master/Server/appsettings.json) for an example.
## Changing the Database
By default, Remotely uses a SQLite database. When first run, it creates a file as specified for the SQLite connection string in appsettings.json.
By default, Remotely uses a SQLite database. When first run, it creates a file as specified for the SQLite connection string in appsettings.json.
You can change database by changing `DBProvider` in `ApplicationOptions` to `SQLServer` or `PostgreSQL`.
## Logging
- On clients, logs are kept in `%ProgramData%\Remotely\Logs`
- Within the server container, logs will be written to `/app/AppData/logs`, which (by default) will be mounted to `/var/www/remotely/Logs` on the host.
- Built-in ASP.NET Core logs are written to the console (stdout). You can redirect this to a file if desired.
- In IIS, this can be done in the web.config file by setting stdoutLogEnabled to true.
- Within the server container, logs will be written to `/app/AppData/logs`, which (by default) will be mounted to `/var/www/remotely/Logs` on the host.
- Built-in ASP.NET Core logs are written to the console (stdout). You can redirect this to a file if desired.
- In IIS, this can be done in the web.config file by setting stdoutLogEnabled to true.
- On Windows Servers, the above logs can also be written to the Windows Event Log.
- This is enabled in Server Config by setting EnableWindowsEventLog to true.
- This is enabled in Server Config by setting EnableWindowsEventLog to true.
- You can configure logging levels and other settings in appsetttings.json.
- More information: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/logging/
- More information: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/logging/
## Remote Control Client Requirements
- Windows: Only the latest version of Windows 11 is tested. Windows 7 and 8.1 should work, though performance will be reduced on Windows 7.
- Windows 2019/2022 should work as well, but isn't tested regularly.
- Windows: Only the latest version of Windows 11 is tested. Windows 7 and 8.1 should work, though performance will be reduced on Windows 7.
- Windows 2019/2022 should work as well, but isn't tested regularly.
- Linux: Only the latest LTS version of Ubuntu is tested.
- For the Ubuntu's "quick support" client, you must first install the following dependencies:
- libx11-dev
- libxrandr-dev
- libx11-dev
- libxrandr-dev
- libc6-dev
- libxtst-dev
- xclip
## Remote Control on Mobile
Ideally, you'd be doing remote control from an actual computer or laptop. However, I've tried to make the remote control at least somewhat usable from a mobile device. Here are the controls:
Ideally, you'd be doing remote control from an actual computer or laptop. However, I've tried to make the remote control at least somewhat usable from a mobile device. Here are the controls:
- Left-click: Single tap
- Right-click: Long-press, then release
- Click-and-drag: Long-press, then drag
## End User Support Page
There's a page at `/get-support` where end users can request support. When the form is submitted, an alert appears on the main page, above the grid.
A shortcut to this page is placed in the `\Program Files\Remotely\` folder. You can copy it anywhere you like. You can also have it copied to the desktop automatically by using the `-supportshortcut` switch on the installer.
There's a page at `/get-support` where end users can request support. When the form is submitted, an alert appears on the main page, above the grid.
A shortcut to this page is placed in the `\Program Files\Remotely\` folder. You can copy it anywhere you like. You can also have it copied to the desktop automatically by using the `-supportshortcut` switch on the installer.
## .NET Deployments
- .NET has two methods of deployment: framework-dependent and self-contained.
- Framework-dependent deployments require the .NET runtime to be installed on the target computers. It must be the same version that was used to build the app.
- Self-contained deployments include a copy of the runtime, so you don't need to install it on the target computers. As a result, the total file size is much larger.
- .NET uses runtime identifiers that are targeted when building.
- Link: https://docs.microsoft.com/en-us/dotnet/core/rid-catalog
- .NET has two methods of deployment: framework-dependent and self-contained.
- Framework-dependent deployments require the .NET runtime to be installed on the target computers. It must be the same version that was used to build the app.
- Self-contained deployments include a copy of the runtime, so you don't need to install it on the target computers. As a result, the total file size is much larger.
- .NET uses runtime identifiers that are targeted when building.
- Link: https://docs.microsoft.com/en-us/dotnet/core/rid-catalog
## Shortcut Keys
There are a few shortcut keys available when using the console.
- / : Slash will allow you to switch between shells. The names are configurable in the Options page.
- / : Slash will allow you to switch between shells. The names are configurable in the Options page.
- Up/Down: Use arrow up/down to cycle through input history.
- Ctrl + Q: Clear the output window.
## Port Configuration
Ports are configured in the `docker-compose.yml` file. If you change the internal port for the container, make sure you update `ASPNETCORE_HTTP_PORTS` variable to match.
Ports are configured in the `docker-compose.yml` file. If you change the internal port for the container, make sure you update `ASPNETCORE_HTTP_PORTS` variable to match.
## API and Integrations
Remotely has a basic API, which can be browsed at `https://{your_server_url}/swagger`. Most endpoints require authentication via an API access token, which can be created by going to Account - API Access.
When accessing the API from the browser on another website, you'll need to set up CORS in appsettings by adding the website origin URL to the TrustedCorsOrigins array. If you're not familiar with how CORS works, I recommend reading up on it before proceeding. For example, if I wanted to create a login form on https://exmaple.com that logged into the Remotely API, I'd need to add "https://example.com" to the TrustedCorsOrigins.
Remotely has a basic API, which can be browsed at `https://{your_server_url}/swagger`. Most endpoints require authentication via an API access token, which can be created by going to Account - API Access.
Each request to the API must have a header named "X-Api-Key". The value should be the API key's ID and secret, separated by a colon (i.e. [ApiKey]:[ApiSecret]).
When accessing the API from the browser on another website, you'll need to set up CORS in appsettings by adding the website origin URL to the TrustedCorsOrigins array. If you're not familiar with how CORS works, I recommend reading up on it before proceeding. For example, if I wanted to create a login form on https://exmaple.com that logged into the Remotely API, I'd need to add "https://example.com" to the TrustedCorsOrigins.
Each request to the API must have a header named "X-Api-Key". The value should be the API key's ID and secret, separated by a colon (i.e. [ApiKey]:[ApiSecret]).
Below is an example API request:
POST https://localhost:5001/API/Scripting/ExecuteCommand/PSCore/f2b0a595-5ea8-471b-975f-12e70e0f3497 HTTP/1.1
Content-Type: application/json
X-Api-Key: 31fb288d-af97-4ce1-ae7b-ceebb98281ac:HLkrKaZGExYvozSPvcACZw9awKkhHnNK
User-Agent: PostmanRuntime/7.22.0
Accept: */*
Cache-Control: no-cache
Host: localhost:5001
Accept-Encoding: gzip, deflate, br
Content-Length: 12
Connection: close
POST https://localhost:5001/API/Scripting/ExecuteCommand/PSCore/f2b0a595-5ea8-471b-975f-12e70e0f3497 HTTP/1.1
Content-Type: application/json
X-Api-Key: 31fb288d-af97-4ce1-ae7b-ceebb98281ac:HLkrKaZGExYvozSPvcACZw9awKkhHnNK
User-Agent: PostmanRuntime/7.22.0
Accept: */*
Cache-Control: no-cache
Host: localhost:5001
Accept-Encoding: gzip, deflate, br
Content-Length: 12
Connection: close
Get-Location
Get-Location
Below are examples of using the cookie-based login API (JavaScript):
// Log in with one request, then launch remote control with another.
fetch("https://localhost:5001/api/Login/", {
method: "post",
credentials: "include",
mode: "cors",
body: '{"email":"email@example.com", "password":"P@ssword1"}',
headers: {
"Content-Type": "application/json",
}
}).then(response=>{
if (response.ok) {
fetch("https://localhost:44351/api/RemoteControl/Viewer/b68c24b0-2c67-4524-ad28-dadea7a576a4", {
method: "get",
credentials: "include",
mode: "cors"
}).then(response=>{
if (response.ok) {
response.text().then(url=>{
window.open(url);
})
}
})
}
})
// Log in with one request, then launch remote control with another.
fetch("https://localhost:5001/api/Login/", {
method: "post",
credentials: "include",
mode: "cors",
body: '{"email":"email@example.com", "password":"P@ssword1"}',
headers: {
"Content-Type": "application/json",
}
}).then(response=>{
if (response.ok) {
fetch("https://localhost:44351/api/RemoteControl/Viewer/b68c24b0-2c67-4524-ad28-dadea7a576a4", {
method: "get",
credentials: "include",
mode: "cors"
}).then(response=>{
if (response.ok) {
response.text().then(url=>{
window.open(url);
})
}
})
}
})
// Log in and launch remote control in the same request.
fetch("https://localhost:5001/api/RemoteControl/Viewer/", {
method: "post",
credentials: "include",
mode: "cors",
body: '{"email":"email@example.com", "password":"P@ssword1", "deviceID":"b68c24b0-2c67-4524-ad28-dadea7a576a4"}',
headers: {
"Content-Type": "application/json",
}
}).then(response=>{
if (response.ok) {
response.text().then(url=>{
window.open(url);
})
}
})
// Log in and launch remote control in the same request.
fetch("https://localhost:5001/api/RemoteControl/Viewer/", {
method: "post",
credentials: "include",
mode: "cors",
body: '{"email":"email@example.com", "password":"P@ssword1", "deviceID":"b68c24b0-2c67-4524-ad28-dadea7a576a4"}',
headers: {
"Content-Type": "application/json",
}
}).then(response=>{
if (response.ok) {
response.text().then(url=>{
window.open(url);
})
}
})
## Alerts
The Alerts API gives you the ability to add monitoring and alerting functionality to your device endpoints. This feature is intended to add basic RMM-type functionality without diverging too far from Remotely's primary purpose.
The Alerts API gives you the ability to add monitoring and alerting functionality to your device endpoints. This feature is intended to add basic RMM-type functionality without diverging too far from Remotely's primary purpose.
Alerts can be set up to show a notification on the Remotely website, send an email, and/or perform a separate API request.
To use Alerts, you'd first need to make an API token (or multiple tokens) for your devices to use. Then create a scheduled task or some other recurring script to do the work. Below is an example of how to use PowerShell to create a Scheduled Job that checks the disk space on a daily schedule.
To use Alerts, you'd first need to make an API token (or multiple tokens) for your devices to use. Then create a scheduled task or some other recurring script to do the work. Below is an example of how to use PowerShell to create a Scheduled Job that checks the disk space on a daily schedule.
```
$Trigger = New-JobTrigger -Daily -At "5 AM"
@ -256,7 +275,7 @@ Register-ScheduledJob -ScriptBlock {
$OsDrive = Get-PSDrive -Name C
$FreeSpace = $OsDrive.Free / ($OsDrive.Used + $OsDrive.Free)
if ($FreeSpace -lt .1) {
Invoke-WebRequest -Uri "https://localhost:5001/api/Alerts/Create/" -Method Post -Headers @{
Invoke-WebRequest -Uri "https://localhost:5001/api/Alerts/Create/" -Method Post -Headers @{
X-Api-Key="3e9d8273-1dc1-4303-bd50-7a133e36b9b7:S+82XKZdvg278pSFHWtUklqHENuO5IhH"
} -Body @"
{