Public/Set-PlexConfiguration.ps1
function Set-PlexConfiguration { <# .SYNOPSIS Obtains an access token for your account and saves it and your server details. .DESCRIPTION Used to save Plex configuration to disk, which is used by all other functions. .PARAMETER Credential Credential object containing your Plex username and password. .EXAMPLE Set-PlexConfiguration -Credential (Get-Credential) #> [CmdletBinding()] param( [Parameter(Mandatory = $true)] [PSCredential] $Credential, [Parameter(Mandatory = $true)] [String] $DefaultServerName ) #Region Get auth token: Write-Verbose -Message "Getting authentication token" try { $Base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $Credential.GetNetworkCredential().UserName, $Credential.GetNetworkCredential().Password))) $Data = Invoke-RestMethod -Uri "https://plex.tv/users/sign_in.json" -Method POST -Headers @{ 'Authorization' = ("Basic {0}" -f $Base64AuthInfo); 'X-Plex-Client-Identifier' = "PowerShell-Test"; 'X-Plex-Product' = 'PowerShell-Test'; 'X-Plex-Version' = "V0.01"; 'X-Plex-Username' = $Credential.GetNetworkCredential().UserName; } -ErrorAction Stop } catch { throw $_ } #EndRegion #Region Get online servers Write-Verbose -Message "Getting list of accessible servers" try { $ResourceData = Invoke-RestMethod -Uri "https://plex.tv/api/v2/resources?includeHttps=1&X-Plex-Token=$($Data.user.authentication_token)&X-Plex-Client-Identifier=PSPlex" -Method GET -UseBasicParsing -Headers @{"Accept" = "application/json, text/plain, */*" } if(!$ResourceData) { throw "Could not get resource data." } Write-Verbose -Message "The following servers were returned: $(($ResourceData.name | Sort-Object) -join ", ")" # Refine to only servers that are online and owned by the user: Write-Verbose -Message "Refining to only owned and online servers." [Array]$OwnedAndOnline = $ResourceData | Where-Object { $_.product -eq 'Plex Media Server' -and $_.owned -eq 1 } if(!$OwnedAndOnline) { throw "No owned servers online." } Write-Verbose -Message "The following servers are owned and online: $(($OwnedAndOnline.name | Sort-Object) -join ", ")" # If in the owned and online servers, there's no match for $DefaultServerName, throw an error: if($OwnedAndOnline.Name -notcontains $DefaultServerName) { throw "The server name '$DefaultServerName' does not match any of the owned and online servers." } # Loop and construct a custom object to store in our configuration file. $ConfigurationData = [System.Collections.ArrayList]@() foreach($Server in $OwnedAndOnline) { # When storing the configuration data for each server we need an accessible uri. # For servers with a public IP address in the .connections.address property, we can use the # .connections.uri property; this will be an address of the format: # https://<public-ip>.someidentifier.plex.direct:32400 # For servers without a public IP in the .connections.address property, this suggests remote # access is turned off. Instead we can construct a locally accessible uri from the following # properties: "http://" + .connections.address + ":" + .connections.port # Note: From my testing even though .connections.protocol is https, it's still accessible over # http and we won't have to do any insecure certificate bypassing. # Note also: .connections.local is useful to show public/private addresses but we can't use it # otherwise we may end up with duplicate entries in the configuration file (one with IP, one with hostname) # .connections property could be an array of objects each with an 'address' property. # Find an address where it's a public IP address and 'uri' matches 'plex.direct': $PublicConnection = $Server.connections | Where-Object { $_.address -notmatch '(^127\.)|(^192\.168\.)|(^10\.)|(^172\.1[6-9]\.)|(^172\.2[0-9]\.)|(^172\.3[0-1]\.)' -and $_.uri -match "plex.direct" } if($PublicConnection) { $Uri = $PublicConnection.uri $Port = $PublicConnection.port } else { # Look for a private connection: $PrivateConnection = $Server.connections | Where-Object { $_.address -match '(^127\.)|(^192\.168\.)|(^10\.)|(^172\.1[6-9]\.)|(^172\.2[0-9]\.)|(^172\.3[0-1]\.)' } if($PrivateConnection) { $Uri = "http://$($PrivateConnection.address):$($PrivateConnection.port)" $Port = $PrivateConnection.port } } if(!$Uri) { # We didn't find a suitable connection to use so skip this server continue } # If the current server name is equal to $DefaultServerName, set the 'Default' property to $true if($Server.name -eq $DefaultServerName) { $Default = $true } else { $Default = $false } Write-Verbose -Message "Adding server $($Server.name) to configuration data." $ConfigurationData.Add( [PSCustomObject]@{ PlexServer = $Server.name Port = $Port PublicAddress = $Server.publicAddress ClientIdentifier = $Server.clientIdentifier Token = $Server.accessToken Uri = $Uri Default = $Default }) | Out-Null } } catch { throw $_ } #EndRegion #Region Save Configuration to disk if($ConfigurationData.Count -gt 0) { try { $ConfigFile = Get-PlexConfigFileLocation -ErrorAction Stop # Create folder if it doesn't exist: if(-not (Test-Path (Split-Path $ConfigFile))) { New-Item -ItemType Directory -Path (Split-Path $ConfigFile) | Out-Null } # Write the configuration data to disk: ConvertTo-Json -InputObject @($ConfigurationData) -Depth 3 -ErrorAction Stop | Out-File -FilePath $ConfigFile -Force -ErrorAction Stop } catch { throw $_ } } else { throw "No servers found." } #EndRegion } |