Commands/Requests/Get-OBSGroupSceneItem.ps1

function Get-OBSGroupSceneItem {
<#
.Synopsis
    
    Get-OBSGroupSceneItem : GetGroupSceneItemList
    
.Description
    Basically GetSceneItemList, but for groups.
    
    Using groups at all in OBS is discouraged, as they are very broken under the hood. Please use nested scenes instead.
    
    Groups only
    
    
    Get-OBSGroupSceneItem calls the OBS WebSocket with a request of type GetGroupSceneItemList.
.Link
    https://github.com/obsproject/obs-websocket/blob/master/docs/generated/protocol.md#getgroupsceneitemlist
#>

[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetGroupSceneItemList')]
[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)]
param(
<# Name of the group to get the items of #>
[Parameter(Mandatory,ValueFromPipelineByPropertyName)]
[ComponentModel.DefaultBindingProperty('sceneName')]
[string]
$sceneName
)


process {


        # Create a copy of the parameters (that are part of the payload)
        $paramCopy = [Ordered]@{}
        # get a reference to this command
        $myCmd = $MyInvocation.MyCommand

        # Keep track of how many requests we have done of a given type
        # (this makes creating RequestIDs easy)
        if (-not $script:ObsRequestsCounts) {
            $script:ObsRequestsCounts = @{}
        }

        # Set my requestType to blank
        $myRequestType = ''
        # and indicate we are not expecting a response
        $responseExpected = $false
        # Then walk over this commands' attributes,
        foreach ($attr in $myCmd.ScriptBlock.Attributes) {
            if ($attr -is [Reflection.AssemblyMetadataAttribute]) {
                if ($attr.Key -eq 'OBS.WebSocket.RequestType') {
                    $myRequestType = $attr.Value # set the requestType,
                }
                elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') {
                    # and determine if we are expecting a response.
                    $responseExpected = 
                        if ($attr.Value -eq 'false') {
                            $false   
                        } else { $true }
                }
            }
        }

        # Walk over each parameter
        :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) {
            # and walk over each of it's attributes to see if it part of the payload
            foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) {
                # If the parameter is bound to part of the payload
                if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) {
                    # copy it into our payload dicitionary.
                    $paramCopy[$attr.Name] = $keyValue.Value
                    # (don't forget to turn switches into booleans)
                    if ($paramCopy[$attr.Name] -is [switch]) {
                        $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name]
                    }
                    continue nextParam
                }
            }
        }

        # If we don't have a request counter for this request type
        if (-not $script:ObsRequestsCounts[$requestType]) {
            # initialize it to zero.
            $script:ObsRequestsCounts[$requestType] = 0
        }
        # Increment the counter for requests of this type
        $script:ObsRequestsCounts[$requestType]++

        # and make a request ID from that.
        $myRequestId = "$myRequestType.$($script:ObsRequestsCounts[$requestType])"

        # Construct the actual payload
        $payloadJson = [Ordered]@{
            op = 6   # All requests are sent with the opcode 6
            d = @{
                # and must include a request ID
                requestId = "$myRequestType.$($script:ObsRequestsCounts[$requestType])"
                # request type
                requestType = $myRequestType
                # and optional data
                requestData = $paramCopy
            }
        } |
            # Once we have constructed the payload, make it JSON
            ConvertTo-Json -Depth 100
        
        # And create a byte segment to send it offf.
        $SendSegment  = [ArraySegment[Byte]]::new([Text.Encoding]::UTF8.GetBytes($PayloadJson))

        # If we have no OBS connections
        if (-not $script:ObsConnections.Values) {
            # error out
            Write-Error "Not connected to OBS. Use Connect-OBS."
            return
        }

        # Otherwise, walk over each connection
        foreach ($obsConnection in $script:ObsConnections.Values) {
            $OBSWebSocket = $obsConnection.Websocket
            if ($VerbosePreference -notin 'silentlyContinue', 'ignore') {
                Write-Verbose "Sending $payloadJSON"
            }
            # and send the payload
            $null = $OBSWebSocket.SendAsync($SendSegment,'Text', $true, [Threading.CancellationToken]::new($false))

            # If a response was expected
            if ($responseExpected) {
                # wait a second for that event
                $eventResponse = Wait-Event -SourceIdentifier $myRequestId -Timeout 1 |
                    Select-Object -ExpandProperty MessageData
                # Collect all properties from the response
                $eventResponseProperties = @($eventResponse.psobject.properties)
                
                $expandedResponse =
                    # If there was only one, expand that property
                    if ($eventResponseProperties.Length -eq 1) {
                        $eventResponse.psobject.properties.value
                    } else {
                        $eventResponse
                    }

                
                # Now walk thru each response and expand / decorate it
                foreach ($responseObject in $expandedResponse) {
                    # If there was no response, move on.
                    if ($null -eq $responseObject) {
                        continue
                    }
                    # If the response is a string and it's the same as the request type
                    if ($responseObject -is [string] -and $responseObject -eq $myRequestType) {
                        continue # ignore it
                    }
                    # otherwise, if the response looks like a file
                    elseif ($responseObject -is [string] -and 
                        $responseObject -match '^(?:\p{L}\:){0,1}[\\/]') {
                        $fileName = $responseObject -replace '[\\/]', ([io.path]::DirectorySeparatorChar)
                        if (Test-Path $fileName) {
                            $responseObject = Get-Item -LiteralPath $fileName
                        }
                    }

                    # Otherwise, create a new PSObject out of the response
                    $responseObject = [PSObject]::new($responseObject)                    
                    # and decorate it with the command name and OBS.requestype.response
                    $responseObject.pstypenames.add("$myCmd")                        
                    $responseObject.pstypenames.add("OBS.$myRequestType.Response")

                    # Now, walk thru all properties in our input payload
                    foreach ($keyValue in $paramCopy.GetEnumerator()) {
                        # If they were not in our output
                        if (-not $responseObject.psobject.properties[$keyValue.Key]) {
                            # add them
                            $responseObject.psobject.properties.add(
                                [psnoteproperty]::new($keyValue.Key, $keyValue.Value)
                            )
                        }

                        # Doing this will make it easier to pipe one step to another
                        # and make results more useful.
                    }

                    # finally, emit our response object
                    $responseObject
                }            
            }    
        }

}

}