2

I am trying to create a script that can force logoff of users in an RDS server farm environment. There are 1 of 4 RDS servers that users can be be logged into, and I am trying to make this so you run the script, enter a username and it will force logoff of the user. So far I have:

import-module remotedesktop
$user = read-host -prompt 'Enter Username you want to disconnect'
$sid = Get-RDUserSession | Where-Object -filter {$_.UserName -eq $user} | format-wide -Property UnifiedSessionID
$server = Get-RDUserSession | Where-Object -filter {$_.UserName -eq $user} | format-wide -Property HostServer
Invoke-RDUserLogoff -HostServer "$server" -UnifiedSessionID $sid

The only problem with this in the last line it doesn't like the $sid variable as the input for that item. If I do a write-output $sid it displays the correct UnifiedSessionID number.

I could be doing this the wrong way altogether, but I just need a way to disconnect user sessions based on a username input when prompted.

mklement0
  • 382,024
  • 64
  • 607
  • 775
  • As an aside: [Using script blocks (`{...}`) as `-Filter` arguments is best avoided](https://stackoverflow.com/a/44184818/45375). – mklement0 May 26 '18 at 02:57

3 Answers3

1

The problem is you never get the UnifiedSessionID store with format-wide

Use select -ExpandProperty

import-module remotedesktop

$user = read-host -prompt 'Enter Username you want to disconnect'

$sid = Get-RDUserSession | Where-Object -filter {$_.UserName -eq $user} | select -ExpandProperty UnifiedSessionID

$server = Get-RDUserSession | Where-Object -filter {$_.UserName -eq $user} | select -ExpandProperty HostServer

Invoke-RDUserLogoff -HostServer "$server" -UnifiedSessionID $sid
Bonneau21
  • 544
  • 1
  • 5
  • 20
1

I could be doing this the wrong way altogether

Indeed:

  • Format-* cmdlets are only meant to produce output for display.

    • Never use them for programmatic processing.
  • For programmatic processing, use Select-Object:

    • Use Select-Object <prop1>, ... to extract multiple properties as a custom object.
    • Use Select-Object -ExpandProperty <prop> to extract a single property's value.

Frédéric Bonneau's helpful answer shows you how to do that in your case.

mklement0
  • 382,024
  • 64
  • 607
  • 775
-1

The $sid variable is being loaded with data whose datatype is the datatype of the last action in the pipeline, i.e., format-wide. So, the datatype of $sid may be something like Microsoft.PowerShell.Commands.Internal.Format.FormatStartData.

You can verify by executing the command $sid | get-member right after $sid is loaded.

It may be that the -UnifiedSessionID argument of Invoke-RDUserLogoff has to be a string, and $sid is not a string

You'll have to cast $sid to string if that's the case

VA systems engineer
  • 2,856
  • 2
  • 14
  • 38
  • That's exactly what the datatype was. Sorry, how exactly would I convert that datatype to a string? – Eric Barger May 25 '18 at 17:17
  • Nevermind I just added `| out-string`to the the end and it works fine now. Thank you so much! – Eric Barger May 25 '18 at 18:10
  • Good to hear - its easy to forget that `PowerShell` `cmdlets` typically accept and emit `object-based` entities. The `Get-Member` `cmdlet` is your friend because it can tell you what the `datatype` is of any object – VA systems engineer May 25 '18 at 20:26
  • While you _may_ situationally be able to retrieve the data underlying the objects produced by `Format-*` cmdlets, the far better approach is to not use those cmdlets in the first place when the intent is _programmatic_ processing of the output. You should make that clear in your answer. – mklement0 May 26 '18 at 02:54
  • @mklement0: Agreed. Your answer addressed the root cause. However, I think we all have to consider that his requirements may also demand a formatted output. If I were to change my answer, I guess I would both address the issue/bug and his original (implied) requirements – VA systems engineer May 26 '18 at 12:22
  • Since command output is being captured in _variables_, there is no display output and therefore no need for formatting. The OP only used `Format-Wide` because it _appeared_ that it extracted the property values of interest, when it reality it created `[Microsoft.PowerShell.Commands.Internal.Format.*]` instances with _formatting instructions_. – mklement0 May 26 '18 at 12:51
  • Furthermore, casting to `[string]` doesn't actually work here; try `[string] (Get-Item / | Format-Wide -Property Name)` – mklement0 May 26 '18 at 12:53