More bugs in the powershell cmdlets

More bugs in the powershell cmdlets

avatar

In response to this post: https://forum.devolutions.net/messages.aspx?TopicID=29181&lastpage=1
I was going to say:
You can pull it from the powershell cmdlets.
Get-RDMSession | where-object { $_.ConnectionType -eq 'Group' }
However, in my quick testing, this doesn't work correctly. Looks like there are more bugs in the updated powershell cmdlets than I realized.

When I run this, I get some of my groups but not all of them (probably missing more than actually get pulled). I had posted a very long message previously about updating the powershell cmdlets, and traded a few posts back and forth with David Hervieux about them, and what I could see as some necessary changes. (And yet another complement.. I don't know of any other company of any size that has their CEO taking part in support forums :-)

Anyway.. this bug has made itself known here. When I run just a Get-RDMSession, it pulls some of the groups, but not all. And my fear is that other items may be missing from the Get-RDMSession. As an example from my case, when I run the Get-RDMSession, and look at some of my groups called 'PRODxx' that range from PROD01 through PROD38, I only get 1,2,3,4,5,19,35,36,37,38. If I try to manually run others like Get-RDMSession -name PROD06, I get a very long error, saying that it doesn't belong to the set... which has most of my connections, if not all of them.

I expect that it is because I created a lot of those groups by powershell script, and if that is the case, then the creation cmdlet is flawed. If this is the case, I could use some help fixing it :-)

On a side note, I did figure out that the Powershell Cmdlet window has display issues when it is run in embedded mode. Once I dragged it out of the main window into a separate window, the console display stopped displaying weird behavior.

And finally, more suggestions to update the powershell module:
1. Make it a true, independent module. Currently, there is some script that runs to load the module, and the cmdlets, which makes it very difficult to load the modules outside of the RDM interface.
2. There should be other RDMGroup commands.. right now, there is a Rename-RDMGroup, but not a New-RDMGroup, Set-RDMGroup, Remove-RDMGroup, etc. From what I can see in the Rename-RDMGroup, I may be misinterpreting what RDMGroup means in this context?
3. The Get-RDMSession should have a filter to make it easier to retrieve the desired connection types, with a prepopulated type list. I.e. Get-RDMSession -ConnectionType Group, or Get-RDMSession -ConnectionType RDPConfigured etc.
4. And unfortunately, the powershell cmdlets still don't "feel" like the real thing. It feels like I am working with a broken concept of what and how the powershell cmdlets should work. i.e. having to use the Set-RDMSession afterwards to make sure the change gets saved, and the syntax feels awkward at times. The Update-RDMUI cmdlet makes sense, but the changes to individual sessions should be immediate and direct (reflection of these changes in the GUI isn't necessary, but would be nice).

I am currently running the beta 13.0.14.0 on Windows 10 x64, build 1709.

I love the product, thank you guys for this!

David F.

All Comments (16)

avatar

Hello,

About your missing groups when you try the Get-RDMSession cmdlet, I think that they are virtual folders. You could try the following, edit one of the folder that isn't listed with the cmdlet and change any property and save the modification. Then, again run the Get-RDMSession cmdlet to see if it will now in the sessions list.

How did you create those group folders? Have they been added directly in the creation of the entry? You have to create the group folder before to be sure that it exists in the database.

About the other items in your post, for number 1, 2 and 4, I will ask an engineer about them.

For the item 3, you can use the -Type parameter to filter for a specific entry type.
Get-RDMSession -Type Group
Best regards,

Érica Poirier

avatar

I tried the -Type group and it didn't work (hence my small paragraph about that); it doesn't seem to be an available parameter.

Sample (help Get-RDMSession -full from my session)


------------------------------------------------------

SYNTAX

Get-RDMSession [-GroupName <String>] [-Name <String>] [-IncludeSubFolders <SwitchParameter>] [-IncludeDocumentsStoredInDatabase <SwitchParameter>]
[-IncludeLocalPlaylists <SwitchParameter>] [-IncludeUserSpecificSettings <SwitchParameter>] [-CaseSensitive <SwitchParameter>] [<CommonParameters>]


------------------------------------------------------


I tried the modification (added a description on the More tab) and saved it.. I still get an error trying to retrieve the missing groups.
I *believe* these are the ones I created with powershell scripts.. I needed to add around 225 sessions that are all near identical other than slight variances in the name. I did this probably 18 months ago, and I can't find my original scripts.. I just tried it again and it seemed to work?
PS C:\> New-RDMSession -Group PROD -Name 'PROD40' -Type Group -Verbose | Set-RDMSession
PS C:\> Update-RDMUI
PS C:\> Get-RDMSession -Name PROD40

Name Group ID
---- ----- --
PROD40 PROD\PROD40 [GUID]


Now, the RDM sessions I originally created in those folders work fine, and I can retrieve them fine.


Is there a way to detect if a folder is a virtual folder or not? If I did that, it certainly wasn't intentional, and I'd be happy to recreate them if need be?


Thanks for the quick reply Erica :-)


David F.

avatar

Another item to add to the "nice to have list" would be some type accelerators for the common GUID's used..
things like:
[rdm.credential.inherited] = '1310CF82-6FAB-4B7A-9EEA-3E2E451CA2CF'
or even [rdminherited] or whatever..


David F.

avatar

And another minor issue.. (now that I'm digging back in....)

if I do a Get-RDMSession -name prod* I get an error back, as opposed to all the matching groups

David F.

avatar

Hello,

First of all, you are right about the Get-RDMSession cmdlet. I made a mistake about it. It is the New-RDMSession cmdlet that has the -Type parameter. Sorry about this one ;)

The Rename-RDMGroup cmdlet was created to be able to rename a group folder and apply the modification to every child of this group folder. If you use the Set-RDMSession cmdlet to change the name of a group folder, the children will not get that modification, the data could be corrupted and you will get unwanted behavior.
A group folder entry type is like any other session type, so for the other operations, the standard cmdlets will work perfectly (New-RDMSession, Set-RDMSession, Remove-RDMSession).

Best regards,

Érica Poirier

avatar

Hello,

About the creation of yours entries related to virtual groups, I can send you a small PowerShell script that will convert these virtual folders to 'physical' folders in the database. Then, you won't get any error messages anymore for those groups.

Best regards,

Érica Poirier

avatar
























































I would like to specifically reply to points 1 and 4.

Regarding loading the PowerShell module outside of RDM, it is already an independent module, at least from the standpoint that it can be loaded without RDM itself being open. However, it's only available on machines that RDM is installed on, and accessing it requires the direct path to the module file because it's not registered in the system. This is less than desirable, but not a show-stopper by any means. I have multiple external scripts that utilize the module just fine with a single command:

Import-Module -Name 'C:\Program Files (x86)\Devolutions\Remote Desktop Manager\RemoteDesktopManager.PowerShellModule.dll'


As for point 4, I think you are lacking understanding of how PowerShell (and by extension, the .NET Framework) actually works. Getting an RDM session object using Get-RDMSession and then having to apply changes to the session by piping the modified object to Set-RDMSession works the same way as Microsoft's Active Directory module, where you use Get-ADUser to get an AD user account object, on which you can then modify certain properties, and then pipe it through Set-ADUser to apply the changes to the Active Directory database. Similarly, you use Get-ACL to obtain a current ACL object for a file or folder, make changes to its properties, and then pipe it back through Set-ACL to apply the changes to the actual ACL on the folder/file in the filesystem. PowerShell is chock full of pairs of Get/Set cmdlets that basically do the exact same thing, just with various other data sources.

I could launch into a very long and boring explanation of how PowerShell and the .NET Framework work on a technical level, but suffice it to say that this is simply the way that it works, and it's not going to change. You shouldn't even want a direct write to a data source on every single property change to an object in local memory, because the overhead from that would destroy your performance. If you want to change 10 properties, that would result in 10 write operations, whereas the way it is, you only have to perform one write operation that changes all 10 properties in the data source at once.

avatar

I like the "long and boring explanations" but that's just the programmer-want-to-be in me. I hate the AD module and the ACL cmdlets; I do most of my AD stuff through the built-in ADSI capabilities (and of course it has its problems also :-) and the Quest Active Roles module. Unforunately, for the ACL's I don't have a lot of choice.

My primary thought about how the RDM cmdlets work was comparing it to the Quest Active Roles and its cmdlets. For example, I can do a 'Get-QADUser -identity <username> | Set-QADUser -<properyname> value' and its done.. I don't have to do anything beyond that. They don't cover all the properties, and for the ones it doesn't I revert to the ADSI capabilities. (And yes, I am fully aware of the need to do the set after the fact for ADSI). I started this original conversation with David H. back when you guys had a lot of double-hyphenated cmdlets. I wrote a very long post and based on the newer cmdlets, a number of my suggestions were implemented.

Thank you for letting me divert for a minute. :-)

The access to the DLL does bring up an interesting point for me.. I had tried it in the past with no luck.. so I tried it again today, and I must be doing something wrong, because it doesn't work for me.

When I run it from powershell outside of RDM:
-----------------------------------------------------

PS C:\> Import-Module -Name 'C:\Program Files (x86)\Devolutions\Remote Desktop Manager\RemoteDesktopManager.PowerShell.dll'
PS C:\> get-module

ModuleType Version Name ExportedCommands
---------- ------- ---- ----------------
Binary 1.0.0.0 CimCmdlets {Export-BinaryMiLog, Get-CimAssociatedInstance, Get-CimClass, Get-CimInstance...}
Manifest 3.1.0.0 Microsoft.PowerShell.Management {Add-Computer, Add-Content, Checkpoint-Computer, Clear-Content...}
Manifest 3.0.0.0 Microsoft.PowerShell.Security {ConvertFrom-SecureString, ConvertTo-SecureString, Get-Acl, Get-AuthenticodeSignature...}
Manifest 3.1.0.0 Microsoft.PowerShell.Utility {Add-Member, Add-Type, Clear-Variable, Compare-Object...}
Manifest 3.0.0.0 Microsoft.WSMan.Management {Connect-WSMan, Disable-WSManCredSSP, Disconnect-WSMan, Enable-WSManCredSSP...}
Script 3.4.0 Pester {AfterAll, AfterEach, Assert-MockCalled, Assert-VerifiableMocks...}
Script 1.2 PSReadline {Get-PSReadlineKeyHandler, Get-PSReadlineOption, Remove-PSReadlineKeyHandler, Set-PSReadlineKeyHandler...}
Binary 13.0.14.0 RemoteDesktopManager.PowerShell


PS C:\> Get-Command -Module RemoteDesktopManager.PowerShell
PS C:\>

-------------------------------------------------------
I don't see any exported cmdlets from the DLL.

When I run it from inside RDM:
-------------------------------------------------------

Resize PowerShell buffer and window size
Loading RDM CmdLet (Module)

PS C:\Program Files (x86)\Devolutions\Remote Desktop Manager> Get-Module

ModuleType Version Name ExportedCommands
---------- ------- ---- ----------------
Manifest 3.1.0.0 Microsoft.PowerShell.Management {Add-Computer, Add-Content, Checkpoint-Computer, Clear-Content...}
Manifest 3.1.0.0 Microsoft.PowerShell.Utility {Add-Member, Add-Type, Clear-Variable, Compare-Object...}
Script 1.2 PSReadline {Get-PSReadlineKeyHandler, Get-PSReadlineOption, Remove-PSReadlineKeyHandler, Set-PSReadlineKeyHandler...}
Binary 1.0 RemoteDesktopManager.PowerShellM... {Add-RDMRoleToUser, Add-RDMSessionAttachment, Close-RDMSession, Copy-RDMSession...}


PS C:\Program Files (x86)\Devolutions\Remote Desktop Manager> Get-Module | Select-Object -Property version -ExpandProperty name
Microsoft.PowerShell.Management
Microsoft.PowerShell.Utility
PSReadline
RemoteDesktopManager.PowerShellModule
PS C:\Program Files (x86)\Devolutions\Remote Desktop Manager> get-command -Module RemoteDesktopManager.PowerShellModule

CommandType Name Version Source
----------- ---- ------- ------
Cmdlet Add-RDMRoleToUser 1.0 RemoteDesktopManager.PowerShellModule
Cmdlet Add-RDMSessionAttachment 1.0 RemoteDesktopManager.PowerShellModule
Cmdlet Close-RDMSession 1.0 RemoteDesktopManager.PowerShellModule
Cmdlet Copy-RDMSession 1.0 RemoteDesktopManager.PowerShellModule
Cmdlet Export-RDMSession 1.0 RemoteDesktopManager.PowerShellModule
Cmdlet Get-RDMCurrentDataSource 1.0 RemoteDesktopManager.PowerShellModule
Cmdlet Get-RDMDataSource 1.0 RemoteDesktopManager.PowerShellModule

..........
-------------------------------------------------------

Erica.. I would definitely appreciate that script..

Thank you both again for the great product & fantastic support.

David F.

avatar

Hello,

I sent you a RDM entry in a private message that includes this script.

Best regards,

Érica Poirier

avatar

Hi,

To import the PowerShell module outside of RDM you can write:

[color=rgb(73, 73, 73)][font="Open Sans", sans-serif]Import-Module -Name 'C:\Program Files (x86)\Devolutions\Remote Desktop Manager\RemoteDesktopManager.PowerShellModule.psd1'[/font][/color]
or
[color=rgb(73, 73, 73)][font="Open Sans", sans-serif]Import-Module -Name 'C:\Program Files (x86)\Devolutions\Remote Desktop Manager\RemoteDesktopManager.PowerShellModule.dll'[/font][/color]
RemoteDesktopManager.PowerShellModule.psd1 is the module manifest that you can also be used to load the module.

The binary module is RemoteDesktopManager.PowerShellModule.dll not RemoteDesktopManager.PowerShell.dll

Best regards,

Olivier Désalliers

avatar







So basically you're looking to simply push a value without needing to first pull and query the existing value, and the only reason you're pulling the session data in the first place is to get the session ID to push the new property value to. I have two comments about that.

1. This makes sense to do in some cases, but not all. For objects that have relatively few properties, it's easy to build in parameter sets that allow you to set all of those properties directly within a Set command. However, for large objects with tons of properties, it becomes less feasible to do this, both because the amount of code needed in the module itself would be insane, and also because the module would constantly have to be updated as any properties on the object are added, modified, or deleted, making it maintenance-heavy. Perhaps a compromise could be made where only the most frequently modified properties could be set via parameters, and anything else would still require the multi-step process, but somebody will always be unhappy with which parameters are supported. And actually, it appears Devolutions already solved this quandary with another cmdlet, which brings me to the next point.

2. It seems that you are unaware of the Set-RDMSessionProperty cmdlet, which does allow you to set properties directly on a session simply by providing a session ID, which you can do by pulling the session with Get-RDMSession and piping it to Set-RDMSessionProperty. I can't say why they chose to make this a separate cmdlet instead of bundling the functionality into Set-RDMSession, but it looks like it will most likely give you the functionality you desire, per the example you provided for Get-QADUser/Set-QADUser.

If you're looking for more of a sysadmin solution where you're manually running commands to update things, and want a single command to set a property, that should do the trick for you. However, if you're writing any kind of automated script that sets multiple properties per session, then for performance reasons, you will want to modify the properties on object in local memory and them push them back using Set-RDMSession as it will be faster than calling multiple Set-RDMSessionProperty commands per session you want to modify.

avatar

Erica: Thank you! it absolutely worked, and did what I needed.
Olivier: Thank you also :-) I missed the 'module' in the dll name.
And Bradley, thank you too.. I wasn't aware of the set-rdmsessionproperty cmdlet. And you are absolutely correct.. 90% of the time I am pushing things on a singular basis, and every now & then I'll use the a bulk import/modification. If I have a lot of them, I'll use a control script with a lot of multi-threading, and on those I typically will grab the entire object in memory, do my modifications and push it back.

David F.

avatar

I'm not looking to revive a "dead" thread per-se.. but I have a reason to dig back into the powershell module, and it is still killing me - its been an incredibly tough road (for me) to get through this, nothing seems to work the way I would expect it to looking at the help for the modules, and looking through the online documentation.

Can you guys give me a practical example of a small script using the Copy-RDMSession cmdlet? my general structure (which is not working) was to do this:

$SourceSession = Get-RDMSession -Name <sessionname>
1..9 | foreach-object {
$NewName = ('server{0}' -f $_)
$NewFullURL = ('https://{0}.domain.tld' -f $NewName)
$NewSession = Copy-RDMSession -PSConnection $SourceSession
$NewSession.Name = $NewName
$NewSession.HostURL = $NewFullURL
$NewSession.HostFull = $NewFullURL
$NewSession | Set-RDMSession
}
Update-RDMUI

That didn't work.. and neither did this stucture:

$SourceSession = Get-RDMSession -Name <sessionname>
1..9 | foreach-object {
$NewName = ('server{0}.domain.tld' -f $_)
$NewFullURL = ('https://{0}' -f $NewName
$NewSession = Copy-RDMSession -PSConnection $SourceSession
Set-RDMSessionProperty -ID $NewSession.ID -Property Name -Value $NewName
Set-RDMSessionProperty -ID $NewSession.ID -Property HostURL -Value $NewFullURL
Set-RDMSessionProperty -ID $NewSession.ID -Property HostFull -Value $NewFullURL
$NewSession | Set-RDMSession
}
Update-RDMUI

Every time, I keep getting warning messages stating 'WARNING: Connection not found.' for each attempt. In the first example, I get one of those for each number, and in the second example, I get one for each Set-RDMSessionProperty command..

(My next step will be to create a loop using New-RDMSession cmdlet, but that seems like it would be very inefficient compared to the Copy-RDMSession. )

And it may seem nitpicky, but the help on all the RDM cmdlets is very sparse, and hasn't been very helpful :-(

Finally.. one more thought about the Set-RDMSessionProperty.. Once I can get this working, it will be helpful; but I'd love to see the functionality expanded where I can send a hashtable (dictionary, etc.) of key-value pairs that would then be applied to the given object. Right now, I'd have to basically set them all individually with one property per line, or parse the hashtable to extract keys & values and then pipe them in. Maybe another named parameterset, like -PropertyHashtable or something like that.

Again... thank you all for an amazing product.

David F.

avatar

Hello,

I have tested your first script and didn't get any error and get the expected results. Does the Get-RDMSession returns a PSConnection object in $SourceSession variable? Are you connected on the right data source/repository?

The other method, I would not recommend you to use it. The reason is just after the copy, you need to save the entry with Set-RDMSession and also need to update the cache with Update-RDMUI cmdlet. Then the Set-RDMSessionProperty can be use to update any properties. But, this is less efficient then creating a new object with the Copy-RDMSession, update all properties directly in the object and then save the object in the data source.

About your comment for the help pages for RDM cmdlets, I will transfer your comment to the Documentation team.

Finally, for your last thing about Set-RDMSessionProperty cmdlet, I will ask Olivier to give you the right information about it.

Best regards,

Érica Poirier

avatar

Hi,

Concerning the hashtable in Set-RDMSessionProperty, do you mean something similar to the cmdlet New-Object as described there: https://blogs.msdn.microsoft.com/powershell/2009/12/04/new-object-psobject-property-hashtable/

Best regards,

Olivier Désalliers

avatar

Thanks Erica.. I will run it again and run a transcript for it to show you what I'm getting. I literally only have the default local source that I back up with your cloud backup. I am glad that it *should* run :-) so that's promising.

Olivier:
That's pretty much exactly what I'm talking about :-)

Once again, you guys rock.. both for the product and the support.

David F