Skip to content

Add Microsoft Azure VM Dynamic Folder for Royal TS on Windows - #142

Open
Ghost93 wants to merge 4 commits into
royalapplications:masterfrom
Ghost93:add-azure-vm-dynamic-folder
Open

Add Microsoft Azure VM Dynamic Folder for Royal TS on Windows#142
Ghost93 wants to merge 4 commits into
royalapplications:masterfrom
Ghost93:add-azure-vm-dynamic-folder

Conversation

@Ghost93

@Ghost93 Ghost93 commented Jul 29, 2026

Copy link
Copy Markdown

Summary

Adds a new Dynamic Folder export under Dynamic Folder/Microsoft Azure/Virtual Machines/:

  • Azure VM (PowerShell).rdfx - importable Dynamic Folder wrapper.
  • Source/Get-AzureVmConnections.ps1 - shared PowerShell 7 script invoked by the wrapper.

The sample manages one Azure virtual machine per Dynamic Folder. On reload it:

  • Starts the VM if it is stopped and waits for the running state.
  • Resolves the primary or named NIC and IP configuration.
  • Waits for each selected connection port.
  • Emits RDP, password-based SSH, and Azure AD-based AzSSH RoyalJSON connections
    with deterministic IDs.

AzSSH uses the Windows Custom Terminal PTY support that was requested in
#141 and shipped in Royal TS v26.
The generated Custom Terminal runs az ssh vm with a forced TTY and Bash login shell,
so Azure CLI performs Azure AD authentication and the embedded terminal keeps history
and arrow keys working correctly.

Requirements (for end users)

  • Windows 11 and Royal TS 26 or newer.
  • PowerShell 7 with the Az module (Install-Module Az -Scope CurrentUser) and a
    cached Connect-AzAccount session.
  • For AzSSH, Azure CLI with SSH extension 2.0.4 or newer and a cached az login session.
  • Royal TS credentials matching CredentialName (RDP) and SshCredentialName (SSH).

Behavior notes

  • RDP and SSH reference Royal TS credentials by name. No password or private key
    is emitted.
  • AzSSH does not use a Royal TS credential; Azure CLI performs the Azure AD sign-in.
  • Public RDP or SSH requires the VM's NSG to permit the selected port from the client.
  • Diagnostics are appended to a synchronized log next to the shared script.
  • Custom Terminal settings (CustomCommandWin, Font, FontSize) are placed inside
    the RoyalJSON Properties dictionary to match the Royal TS 26 rJSON contract.

Testing

  • tools/ToolboxIndex generator runs cleanly against the new directory.
  • Extracted Azure VM (PowerShell).script.autogen.ps1 and the source script
    parse without errors under PowerShell 7.
  • The source script in -TestMode emits three connections (RDP, SSH,
    CustomTerminal) with the AzSSH CustomCommandWin inside Properties
    and Font/FontSize scalars.
  • Verified manually on Windows 11 against a real Azure VM in Royal TS 26,
    including embedded Custom Terminal AzSSH.
  • Reviewer imports the .rdfx in Royal TS 26 and confirms the generated
    connections open.

Adds a new Dynamic Folder sample under Dynamic Folder/Microsoft Azure/
Virtual Machines/ that starts one Azure VM if needed, resolves its IP,
waits for the selected connection ports, and emits RDP, password-based
SSH, and Azure AD-based AzSSH RoyalJSON connections.

AzSSH uses the Windows Custom Terminal PTY support requested in royalapplications#141 and
available in Royal TS v26.
@Ghost93
Ghost93 marked this pull request as ready for review July 29, 2026 06:28
@sargola

sargola commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator

Thanks for this - the deterministic IDs, credential-by-name approach, and validation are well above what most contributions arrive with, and it's nice to see #141 put to use so quickly.

I'm going to decline it in its current form, for two design reasons:

Not self-contained: Every sample here is a single importable .rdfx.
This one asks users to download a .ps1 by hand and set ScriptPath, so the script isn't versioned with the folder that uses it and the master link means later changes reach everyone who already imported it. That wasn't the wrong instinct on your part - a he .rdfx would be deleted by our ToolboxIndex cleanup - but I'd rather not sanction a second
layout for samples.

Reload starts the VM. Startrue and isn't
exposed as a Custom Property, so it can't be turned off without editing the script. Reloading a folder is frcit; it shouldn't
create Azure state and cost. A sample should show how to reach a VM - starting it is a separate, opt-in decisio

Maybe its possible to make the default false for starting the VM automatically?

Ghost93 added 3 commits July 31, 2026 00:28
Prepare for embedding the PS7 script inline in the .rdfx wrapper so
the sample is a single self-contained importable file. The wrapper
update follows in the next commit.
Per reviewer feedback, every sample must be a single importable .rdfx.
The PS5.1 wrapper now embeds the full PS7 logic as a single-quoted
here-string, writes it to a temp .ps1 file, invokes pwsh.exe -File
against it, and deletes the temp file in a finally block.

The wrapper also passes an explicit -LogPath under %LOCALAPPDATA% so
diagnostics survive across runs (previously derived from $PSScriptRoot).

The ScriptPath Custom Property is removed and the Notes are updated to
drop the download-and-configure step.
StartIfStopped in the embedded PS7 script now defaults to $false. A new
StartVm Custom Property (Text, default 'false') lets users opt in per
Dynamic Folder; the wrapper reads it and passes -StartIfStopped to PS7.

Reloading a Dynamic Folder without enabling StartVm no longer silently
starts a stopped VM. Instead the script throws, the outer catch writes
an ERROR log line plus stderr, and exits with code 1 - Royal TS surfaces
this as an error icon on the folder with the message in the UI.
@Ghost93

Ghost93 commented Jul 30, 2026

Copy link
Copy Markdown
Author

Thanks for the detailed review, @sargola - both points are valid. I've pushed two follow-up commits addressing them:

Self-contained (2aa4b29). The full PS7 worker is now embedded inline in the .rdfx as a single-quoted here-string. On reload, the PS5.1 wrapper writes it to a .ps1 under %TEMP%, invokes pwsh.exe -File against it, then deletes the temp file in a finally block. The ScriptPath Custom Property and the Source/Get-AzureVmConnections.ps1 file are gone; import is now a single .rdfx. Diagnostics moved to %LOCALAPPDATA%\RoyalTS\AzureVmDynamicFolder\logs\ so they survive across runs.

Reload no longer starts the VM (b580af0). $StartIfStopped in the embedded script now defaults to $false. A new StartVm Custom Property (default false) lets users opt in per Dynamic Folder. When StartVm=false and the VM is stopped, the script throws, the outer catch logs an ERROR line + writes to stderr, and exits 1 - Royal TS surfaces this as an error icon on the folder with the message in the UI.

Ready for another look when you have a moment.

@StefanKoell

Copy link
Copy Markdown
Member

Thanks for the follow-up, @Ghost93. The two original design concerns are addressed structurally: the submission is now self-contained, and starting the VM is opt-in. I took another pass through the wrapper, embedded worker, generated notes, and security-sensitive behavior.

There is one blocking issue before this can be merged:

StartVm currently prevents every reload. The Custom Property reaches the wrapper as the string false or true, but the worker declares StartIfStopped as [bool]. Since arguments passed through pwsh.exe -File arrive as literal strings, PowerShell cannot bind either value to the Boolean parameter.

I reproduced the complete PS5.1-wrapper-to-PS7-worker path with the default StartVm=false; it exits with code 1 before reaching any Azure logic:

Cannot convert value "System.String" to type "System.Boolean".
Boolean parameters accept only Boolean values and numbers.

The cleanest fix would be to make StartIfStopped a [switch], validate StartVm in the wrapper, and only append -StartIfStopped when the value is true.

A few additional items should be addressed:

  • Please add -NoProfile when starting pwsh.exe. A PowerShell profile that writes anything to stdout can corrupt the RoyalJSON output, and profile errors or customizations make reload behavior machine-dependent.
  • When StartVm=true, the generated AzSSH command also runs az vm start whenever the connection is opened. The notes currently describe StartVm only as controlling startup during Dynamic Folder reload. Please either remove that second startup action or document the behavior, cost implications, and additional Azure CLI permissions.
  • The Azure prerequisites should document the necessary permissions and VM configuration. In particular, the PowerShell identity needs access to read the VM, instance state, NIC, and public IP, plus VM start permission when enabled. Entra SSH additionally requires the VM login extension/managed identity and the Virtual Machine User Login or Virtual Machine Administrator Login role.
  • Please expose or remove DisableFileLogging. The log is enabled permanently, contains resource names, IP addresses, and Azure error details, and currently has no rotation. At minimum, the notes should explain its contents and retention.
  • It would also be great if you can update the PR description. It still references the removed source script, says the VM is started unconditionally, describes logging beside the shared script, and mentions named NIC/IP configuration even though those settings are not exposed by the wrapper.
  • Since the child process explicitly uses -ExecutionPolicy Bypass, that should be disclosed in the notes. It would also be good to validate SubscriptionId as a GUID and tighten the values inserted into the generated cmd.exe command.

Once the Boolean binding issue and the documentation/security points above are addressed, I’m happy to take another look.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants