SteamPS.psm1
#Region '.\Enum\Enum.ps1' 0 enum ServerType { Dedicated = 0x64 #d NonDedicated = 0x6C #l SourceTV = 0x70 #p } enum OSType { Linux = 108 #l Windows = 119 #w Mac = 109 #m MacOsX = 111 #o } enum VAC { Unsecured = 0 Secured = 1 } enum Visibility { Public = 0 Private = 1 } enum PersonaState { Offline = 0 Online = 1 Busy = 2 Away = 3 Snooze = 4 LookingToTrade = 5 } enum CommunityVisibilityState { Private = 1 FriendsOnly = 2 Public = 3 } if ($PSVersionTable.PSVersion.Major -le 5 -and $PSVersionTable.PSVersion.Minor -le 1) { Write-Warning -Message "The support for Windows PowerShell (v5) will be deprecated in the next major version of SteamPS. Please ensure your system supports PowerShell 7." } #EndRegion '.\Enum\Enum.ps1' 38 #Region '.\Private\API\Get-SteamAPIKey.ps1' 0 function Get-SteamAPIKey { <# .SYNOPSIS Grabs API key secure string from file and converts back to plaintext. .DESCRIPTION Grabs API key secure string from file and converts back to plaintext. .EXAMPLE Get-SteamAPIKey Returns the API key secure string in plain text. .NOTES Author: sysgoblin (https://github.com/sysgoblin) and Frederik Hjorslev Poulsen #> [CmdletBinding()] Param ( ) begin { Write-Verbose -Message "[BEGIN ] Starting: $($MyInvocation.MyCommand)" } process { $SteamPSKey = Test-Path -Path "$env:AppData\SteamPS\SteamPSKey.json" if (-not $SteamPSKey) { $Exception = [Exception]::new("Steam Web API configuration file not found in '$env:AppData\SteamPS\SteamPSKey.json'. Run Connect-SteamAPI to configure an API key.") $ErrorRecord = [System.Management.Automation.ErrorRecord]::new( $Exception, 'SteamAPIKeyNotFound', [System.Management.Automation.ErrorCategory]::ObjectNotFound, $SteamPSKey # usually the object that triggered the error, if possible ) $PSCmdlet.ThrowTerminatingError($ErrorRecord) } # cmdlet terminates here, no need for an `else`, only possible way to be here is # if previous condition was false try { $Config = Get-Content "$env:AppData\SteamPS\SteamPSKey.json" $APIKeySecString = $Config | ConvertTo-SecureString [System.Net.NetworkCredential]::new('', $APIKeySecString).Password } catch { $Exception = [Exception]::new("Could not decrypt API key from configuration file not found in '$env:AppData\SteamPS\SteamPSKey.json'. Run Connect-SteamAPI to configure an API key.") $ErrorRecord = [System.Management.Automation.ErrorRecord]::new( $Exception, 'InvalidAPIKey', [System.Management.Automation.ErrorCategory]::ParserError, $APIKey # usually the object that triggered the error, if possible ) $PSCmdlet.ThrowTerminatingError($ErrorRecord) } } # Process end { Write-Verbose -Message "[END ] Ending: $($MyInvocation.MyCommand)" } } # Cmdlet #EndRegion '.\Private\API\Get-SteamAPIKey.ps1' 60 #Region '.\Private\Server\Add-EnvPath.ps1' 0 function Add-EnvPath { <# .LINK https://gist.github.com/mkropat/c1226e0cc2ca941b23a9 #> [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [string]$Path, [ValidateSet('Machine', 'User', 'Session')] [string]$Container = 'Session' ) process { Write-Verbose -Message "Container is set to: $Container" $Path = $Path.Trim() $containerMapping = @{ Machine = [EnvironmentVariableTarget]::Machine User = [EnvironmentVariableTarget]::User Session = [EnvironmentVariableTarget]::Process } $containerType = $containerMapping[$Container] $persistedPaths = [Environment]::GetEnvironmentVariable('Path', $containerType). Split([System.IO.Path]::PathSeparator).Trim() -ne '' if ($persistedPaths -notcontains $Path) { # previous step with `Trim()` + `-ne ''` already takes care of empty tokens, # no need to filter again here $persistedPaths = ($persistedPaths + $Path) -join [System.IO.Path]::PathSeparator [Environment]::SetEnvironmentVariable('Path', $persistedPaths, $containerType) Write-Verbose -Message "Adding $Path to environment path." } else { Write-Verbose -Message "$Path is already located in env:Path." } } # Process } # Cmdlet #EndRegion '.\Private\Server\Add-EnvPath.ps1' 42 #Region '.\Private\Server\Get-PacketString.ps1' 0 function Get-PacketString { <# .SYNOPSIS Get a string in a byte stream. .DESCRIPTION Get a string in a byte stream. .PARAMETER Stream Accepts BinaryReader. .EXAMPLE Get-PacketString -Stream $Stream Assumes that you already have a byte stream. See more detailed usage in Get-SteamServerInfo. .NOTES Author: Jordan Borean and Chris Dent #> [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [System.IO.BinaryReader]$Stream ) process { # Check if the stream has any bytes available if ($Stream.BaseStream.Length -gt 0) { # Find the end of the string, terminated with \0 and convert that byte range to a string. $stringBytes = while ($true) { $byte = $Stream.ReadByte() if ($byte -eq 0) { break } $byte } } if ($stringBytes.Count -gt 0) { [System.Text.Encoding]::UTF8.GetString($stringBytes) } } # Process } # Cmdlet #EndRegion '.\Private\Server\Get-PacketString.ps1' 46 #Region '.\Private\Server\Get-SteamPath.ps1' 0 function Get-SteamPath { [CmdletBinding()] param ( ) process { $SteamCMDPath = $env:Path.Split([System.IO.Path]::PathSeparator) | Where-Object -FilterScript { $_ -like '*SteamCMD*' } if ($null -ne $SteamCMDPath) { [PSCustomObject]@{ 'Path' = $SteamCMDPath 'Executable' = "$SteamCMDPath\steamcmd.exe" } } else { Write-Verbose -Message 'SteamCMD where not found on the environment path.' } } # Process } # Cmdlet #EndRegion '.\Private\Server\Get-SteamPath.ps1' 20 #Region '.\Private\Server\Test-Admin.ps1' 0 function Test-Admin { <# .SYNOPSIS Checks whether the current user has administrator privileges. .DESCRIPTION This cmdlet verifies if the current user has administrator privileges on the system. .EXAMPLE PS C:\> Test-Admin True This example checks if the current user has administrator privileges and returns True if they do. .NOTES Author: Marius Storhaug <https://github.com/PSModule/Admin> #> [OutputType([System.Boolean])] [CmdletBinding()] [Alias('Test-Administrator', 'IsAdmin', 'IsAdministrator')] param ( ) begin { Write-Verbose -Message "[BEGIN ] Starting: $($MyInvocation.MyCommand)" } process { $IsUnix = $PSVersionTable.Platform -eq 'Unix' if ($IsUnix) { Write-Verbose -Message "Running on Unix, checking if user is root." $whoAmI = $(whoami) Write-Verbose -Message "whoami: $whoAmI" $IsRoot = $whoAmI -eq 'root' Write-Verbose -Message "IsRoot: $IsRoot" $IsRoot } else { Write-Verbose -Message "Running on Windows, checking if user is an Administrator." $User = [Security.Principal.WindowsIdentity]::GetCurrent() $Principal = New-Object Security.Principal.WindowsPrincipal($User) $isAdmin = $Principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) Write-Verbose -Message "IsAdmin: $isAdmin" $isAdmin } } end { Write-Verbose -Message "[END ] Ending: $($MyInvocation.MyCommand)" } } #EndRegion '.\Private\Server\Test-Admin.ps1' 51 #Region '.\Public\API\Connect-SteamAPI.ps1' 0 function Connect-SteamAPI { <# .SYNOPSIS Create or update the Steam Web API config file. .DESCRIPTION Create or update the Steam Web API config file which contains the API key used to authenticate to those Steam Web API's that require authentication. .EXAMPLE Connect-SteamAPI Prompts the user for a Steam Web API key and sets the specified input within the config file. .INPUTS None. You cannot pipe objects to Connect-SteamAPI. .OUTPUTS None. Nothing is returned when calling Connect-SteamAPI. .NOTES Author: sysgoblin (https://github.com/sysgoblin) and Frederik Hjorslev Nylander .LINK https://hjorslev.github.io/SteamPS/Connect-SteamAPI.html #> [CmdletBinding()] param ( ) begin { Write-Verbose -Message "[BEGIN ] Starting: $($MyInvocation.MyCommand)" } process { if (-not (Test-Path -Path "$env:AppData\SteamPS\SteamPSKey.json")) { try { $TargetObject = New-Item -Path "$env:AppData\SteamPS\SteamPSKey.json" -Force Write-Verbose -Message "Created config file at $env:AppData\SteamPS\SteamPSKey.json" } catch { $Exception = [Exception]::new("Unable to create file $env:AppData\SteamPS\SteamPSKey.json") $ErrorRecord = [System.Management.Automation.ErrorRecord]::new( $Exception, "CreateSteamAPIKeyFailed", [System.Management.Automation.ErrorCategory]::WriteError, $TargetObject # usually the object that triggered the error, if possible ) $PSCmdlet.ThrowTerminatingError($ErrorRecord) } } $APIKey = Read-Host -Prompt 'Enter your Steam Web API key' -AsSecureString $Key = ConvertFrom-SecureString -SecureString $APIKey $Key | Out-File "$($env:AppData)\SteamPS\SteamPSKey.json" -Force Write-Verbose -Message "Saved key as secure string to config file." } # Process end { Write-Verbose -Message "[END ] Ending: $($MyInvocation.MyCommand)" } } # Cmdlet #EndRegion '.\Public\API\Connect-SteamAPI.ps1' 64 #Region '.\Public\API\Disconnect-SteamAPI.ps1' 0 function Disconnect-SteamAPI { <# .SYNOPSIS Disconnects from the Steam API by removing the stored API key. .DESCRIPTION The Disconnect-SteamAPI cmdlet removes the stored Steam API key from the system. This effectively disconnects the current session from the Steam API. .PARAMETER Force When the Force switch is used, the cmdlet will skip the confirmation prompt and directly remove the API key. .EXAMPLE Disconnect-SteamAPI -Force This command will remove the stored Steam API key without asking for confirmation. .INPUTS None. You cannot pipe objects to Disconnect-SteamAPI. .OUTPUTS None. Nothing is returned when calling Disconnect-SteamAPI. .NOTES Author: Frederik Hjorslev Nylander .LINK https://hjorslev.github.io/SteamPS/Disconnect-SteamAPI.html #> [CmdletBinding()] param ( [Parameter(Mandatory = $false, HelpMessage = 'Skip the confirmation prompt.')][switch]$Force ) begin { Write-Verbose -Message "[BEGIN ] Starting: $($MyInvocation.MyCommand)" $SteamAPIKey = "$env:AppData\SteamPS\SteamPSKey.json" } process { if ($Force -or $PSCmdlet.ShouldContinue($SteamAPIKey, 'Do you want to continue removing the API key?')) { if (Test-Path -Path $SteamAPIKey) { Remove-Item -Path $SteamAPIKey -Force Write-Verbose -Message "$SteamAPIKey were deleted." } else { $Exception = [Exception]::new("Steam Web API configuration file not found in '$env:AppData\SteamPS\SteamPSKey.json'.") $ErrorRecord = [System.Management.Automation.ErrorRecord]::new( $Exception, 'SteamAPIKeyNotFound', [System.Management.Automation.ErrorCategory]::ObjectNotFound, $SteamPSKey ) $PSCmdlet.ThrowTerminatingError($ErrorRecord) } } } end { Write-Verbose -Message "[END ] Ending: $($MyInvocation.MyCommand)" } } #EndRegion '.\Public\API\Disconnect-SteamAPI.ps1' 63 #Region '.\Public\API\Get-SteamApp.ps1' 0 function Get-SteamApp { <# .SYNOPSIS Retrieves the name and ID of a Steam application by searching the name or ID of the application. .DESCRIPTION This function searches for a Steam application by name or ID and returns the corresponding application ID and name. If multiple applications are found, the user can select the correct one from a list. .PARAMETER ApplicationName The name of the application to search for. If multiple applications are found, the user will be presented with a list from which they can select the correct application. .PARAMETER ApplicationID The unique identifier for a Steam application. Use this parameter to search for an application by its ID. .EXAMPLE Get-SteamApp -ApplicationName 'Ground Branch' Searches for applications with names that start with 'Ground Branch'. If multiple applications are found, the user can choose between them, such as the game 'Ground Branch' or 'Ground Branch Dedicated Server'. .EXAMPLE Get-SteamApp -ApplicationID 440 Searches for the application with the AppID 440 and returns its name and ID. .INPUTS System.String or System.Int32. Get-SteamApp accepts either a string value for the application name or an integer value for the application ID. .OUTPUTS PSCustomObject. This function returns a custom object with the application name and application ID. .NOTES Author: Frederik Hjorslev Nylander .LINK https://hjorslev.github.io/SteamPS/Get-SteamApp.html #> [CmdletBinding(DefaultParameterSetName = 'ApplicationName')] [Alias('Find-SteamAppID')] param ( [Parameter(ParameterSetName = 'ApplicationName', Position = 0, Mandatory = $true, ValueFromPipelineByPropertyName = $true )] [Alias('GameName')] [string]$ApplicationName, [Parameter(ParameterSetName = 'ApplicationID', Position = 0, Mandatory = $true, ValueFromPipelineByPropertyName = $true )] [Alias('GameID')] [int]$ApplicationID ) begin { Write-Verbose -Message 'Fetching app list from Steam Web API.' $SteamApps = (Invoke-RestMethod -Uri 'https://api.steampowered.com/ISteamApps/GetAppList/v2/' -UseBasicParsing).applist.apps } process { # ParameterSet ApplicationName if ($PSCmdlet.ParameterSetName -eq 'ApplicationName') { Write-Verbose -Message 'ParameterSetName is ApplicationName' # Filter on ApplicationName. Might result in multiple hits. # The user can then later choose their preference. $FilteredApps = $SteamApps.Where({ $_.name -match "^$ApplicationName" }) # If only one application is found when searching by application name. if (($FilteredApps | Measure-Object).Count -eq 1 -and $null -ne $FilteredApps) { Write-Verbose -Message "Only one application found: $($FilteredApps.name) - $($FilteredApps.appid)." [PSCustomObject]@{ ApplicationID = $FilteredApps.appid ApplicationName = $FilteredApps.name } } # If more than one application is found, the user is prompted to select the exact application. elseif (($FilteredApps | Measure-Object).Count -ge 1) { # An Out-GridView is presented to the user where the exact AppID can be located. This variable contains the AppID selected in the Out-GridView. $SteamApp = $FilteredApps | Select-Object @{Name = 'appid'; Expression = { $_.appid.toString() } }, name | Out-GridView -Title 'Select application' -PassThru if ($SteamApp) { Write-Verbose -Message "$(($SteamApp).name) - $(($SteamApp).appid) selected from Out-GridView." [PSCustomObject]@{ ApplicationID = $SteamApp.appid ApplicationName = $SteamApp.name } } } if (-not $FilteredApps) { $Exception = [Exception]::new("$ApplicationName could not be found.") $ErrorRecord = [System.Management.Automation.ErrorRecord]::new( $Exception, 'ApplicationNotFound', [System.Management.Automation.ErrorCategory]::ObjectNotFound, $FilteredApps ) $PSCmdlet.WriteError($ErrorRecord) } } # ParameterSet ApplicationID elseif ($PSCmdlet.ParameterSetName -eq 'ApplicationID') { Write-Verbose -Message 'ParameterSetName is ApplicationID.' $SteamApp = $SteamApps.Where({ $_.appid -eq $ApplicationID }) if ($SteamApp) { [PSCustomObject]@{ ApplicationID = $SteamApp.appid ApplicationName = $SteamApp.name } } else { $Exception = [Exception]::new("$ApplicationID could not be found.") $ErrorRecord = [System.Management.Automation.ErrorRecord]::new( $Exception, 'ApplicationNotFound', [System.Management.Automation.ErrorCategory]::ObjectNotFound, $SteamApp ) $PSCmdlet.WriteError($ErrorRecord) } } } # Process } # Cmdlet #EndRegion '.\Public\API\Get-SteamApp.ps1' 127 #Region '.\Public\API\Get-SteamFriendList.ps1' 0 function Get-SteamFriendList { <# .SYNOPSIS Fetches the friend list of the specified Steam user. .DESCRIPTION This cmdlet fetches the friend list of a Steam user using the provided SteamID64. It retrieves data only from public profiles. .PARAMETER SteamID64 The 64-bit Steam ID of the user whose friend list is to be fetched. .PARAMETER Relationship The relationship type used to filter the friend list. The possible values are 'all' or 'friend'. The default is 'friend'. .EXAMPLE Get-SteamFriendList -SteamID64 76561197960435530 This example fetches the friend list of the user with the specified SteamID64. .INPUTS System.Int64 .OUTPUTS PSCustomObject. It returns the following properties: - SteamID64: The friend's 64-bit Steam ID. - Relationship: The qualifier of the relationship. - FriendSince: The Unix timestamp indicating when the relationship was established. .NOTES Author: Frederik Hjorslev Nylander .LINK https://hjorslev.github.io/SteamPS/Get-SteamFriendList.html #> [CmdletBinding()] param ( [Parameter(Mandatory = $true, HelpMessage = 'Specifies the 64-bit Steam ID of the user whose friend list will be retrieved.', ValueFromPipelineByPropertyName = $true)] [int64]$SteamID64, [Parameter(Mandatory = $false, HelpMessage = 'Specifies the relationship type to filter the friend list. Possible values are "all" or "friend". Default is "friend".')] [ValidateSet('all', 'friend')] [string]$Relationship = 'friend' ) begin { Write-Verbose -Message "[BEGIN ] Starting: $($MyInvocation.MyCommand)" } process { $Request = Invoke-RestMethod -Uri 'https://api.steampowered.com/ISteamUser/GetFriendList/v1/' -UseBasicParsing -ErrorAction SilentlyContinue -Body @{ key = Get-SteamAPIKey steamid = $SteamID64 relationship = $Relationship } if ($Request) { foreach ($Item in $Request.friendslist.friends) { [PSCustomObject]@{ SteamID64 = [int64]$Item.steamid Relationship = $Item.relationship FriendSince = ((Get-Date "01.01.1970") + ([System.TimeSpan]::FromSeconds($Item.friend_since))).ToString("yyyy-MM-dd HH:mm:ss") } } } elseif ($null -eq $Request) { $Exception = [Exception]::new("No friend list found for $SteamID64. This might be because the profile is private.") $ErrorRecord = [System.Management.Automation.ErrorRecord]::new( $Exception, 'NoFriendsListFound', [System.Management.Automation.ErrorCategory]::ObjectNotFound, $Request ) $PSCmdlet.WriteError($ErrorRecord) } } # Process end { Write-Verbose -Message "[END ] Ending: $($MyInvocation.MyCommand)" } } # Cmdlet #EndRegion '.\Public\API\Get-SteamFriendList.ps1' 84 #Region '.\Public\API\Get-SteamNews.ps1' 0 function Get-SteamNews { <# .SYNOPSIS Fetches the latest news for a game using its AppID. .DESCRIPTION Fetches the latest news for a game using its AppID from the Steam API. .PARAMETER AppID The AppID of the game for which the news is to be fetched. .PARAMETER Count The number of news entries to fetch. By default, it fetches all news entries. .PARAMETER MaxLength The maximum length for each news entry. Entries longer than this will be truncated. By default, there is no truncation. .EXAMPLE Get-SteamNews -AppID 440 This example fetches all available news entries for the game with AppID 440. .EXAMPLE Get-SteamNews -AppID 440 -Count 1 This example fetches the most recent news entry for the game with AppID 440. .EXAMPLE Get-SteamNews -AppID 440 -MaxLength 100 This example fetches all available news entries for the game with AppID 440 and truncates the news content to 100 characters. .INPUTS System.Int32 .OUTPUTS Outputs an object containing: - GID: The ID of the news item. - Title: The title of the news item. - Url: The URL of the news item. - IsExternalUrl: A boolean indicating if the URL is external. - Author: The author of the news item. - Contents: The content of the news item. - FeedLabel: The label of the news feed. - Date: The date and time when the news item was published. - FeedName: The name of the news feed. - FeedType: The type of the news feed. - AppID: The AppID of the game associated with the news item. .NOTES Author: Frederik Hjorslev Nylander .LINK https://hjorslev.github.io/SteamPS/Get-SteamNews.html #> [CmdletBinding()] param ( [Parameter(Mandatory = $true, HelpMessage = 'Specifies the AppID of the game for which you want to retrieve news.')] [int]$AppID, [Parameter(Mandatory = $false, HelpMessage = 'Specifies the number of news entries to retrieve.')] [int]$Count, [Parameter(Mandatory = $false, HelpMessage = 'Specifies the maximum length of each news entry.')] [int]$MaxLength ) begin { Write-Verbose -Message "[BEGIN ] Starting: $($MyInvocation.MyCommand)" } process { # TODO: When only supporting pwsh use null coalescing operator (??) # to handle the case when $Count or $MaxLength is not defined $Body = @{ appid = $AppID } if ($Count) { $Body.Add('count', $Count) } if ($MaxLength) { $Body.Add('maxlength', $MaxLength) } $Request = Invoke-RestMethod -Uri 'http://api.steampowered.com/ISteamNews/GetNewsForApp/v0002/' -UseBasicParsing -Body $Body if ($Request) { foreach ($Item in $Request.appnews.newsitems) { [PSCustomObject]@{ GID = [int64]$Item.gid Title = $Item.title Url = $Item.url IsExternalUrl = [bool]$Item.is_external_url Author = $Item.author Contents = $Item.contents FeedLabel = $Item.feedlabel Date = ((Get-Date "01.01.1970") + ([System.TimeSpan]::FromSeconds($Item.date))).ToString("yyyy-MM-dd HH:mm:ss") FeedName = $Item.feedname FeedType = $Item.feed_type AppID = $Item.appid } } } elseif ($null -eq $Request) { $Exception = [Exception]::new("No news found for $AppID.") $ErrorRecord = [System.Management.Automation.ErrorRecord]::new( $Exception, 'NoNewsFound', [System.Management.Automation.ErrorCategory]::ObjectNotFound, $Request ) $PSCmdlet.WriteError($ErrorRecord) } } # Process end { Write-Verbose -Message "[END ] Ending: $($MyInvocation.MyCommand)" } } # Cmdlet #EndRegion '.\Public\API\Get-SteamNews.ps1' 123 #Region '.\Public\API\Get-SteamPlayerBan.ps1' 0 function Get-SteamPlayerBan { <# .SYNOPSIS Fetches ban information for Steam players. .DESCRIPTION This cmdlet fetches ban information about Steam players. The information includes whether the players are banned from the Steam Community, have VAC bans, the number of VAC bans, days since the last ban, number of game bans, and economy ban status. .PARAMETER SteamID64 Specifies one or more 64-bit Steam IDs for which to fetch ban information. Enter the Steam IDs as a comma-separated list. .EXAMPLE Get-SteamPlayerBan -SteamID64 76561197960435530,76561197960434622 This example fetches ban information for the players with the specified Steam IDs. .INPUTS int64[]: Specifies an array of 64-bit integers representing Steam IDs. .OUTPUTS Returns a PSCustomObject with the following properties: - SteamID64: The player's 64-bit ID. - CommunityBanned: A boolean indicating whether the player is banned from the Steam Community. - VACBanned: A boolean indicating whether the player has VAC bans on record. - NumberOfVACBans: The number of VAC bans on record. - DaysSinceLastBan: The number of days since the last ban. - NumberOfGameBans: The number of bans in games, including CS:GO Overwatch bans. - EconomyBan: The player's ban status in the economy. If the player has no bans on record, the string will be "none". If the player is on probation, it will say "probation", etc. .NOTES Author: Frederik Hjorslev Nylander .LINK https://hjorslev.github.io/SteamPS/Get-SteamPlayerBan.html #> [CmdletBinding()] param ( [Parameter(Mandatory = $true, HelpMessage = '64 bit Steam ID to return player bans for.', ValueFromPipelineByPropertyName = $true)] [int64[]]$SteamID64 ) begin { Write-Verbose -Message "[BEGIN ] Starting: $($MyInvocation.MyCommand)" } process { $Request = Invoke-RestMethod -Uri 'https://api.steampowered.com/ISteamUser/GetPlayerBans/v1/' -UseBasicParsing -Body @{ key = Get-SteamAPIKey steamids = ($SteamID64 -join ',') } if (-not [string]::IsNullOrEmpty($Request.players.SteamId)) { foreach ($Item in $Request.players) { [PSCustomObject]@{ SteamID64 = [int64]$Item.SteamId CommunityBanned = $Item.CommunityBanned VACBanned = $Item.VACBanned NumberOfVACBans = $Item.NumberOfVACBans DaysSinceLastBan = $Item.DaysSinceLastBan NumberOfGameBans = $Item.NumberOfGameBans EconomyBan = $Item.EconomyBan } } } elseif ([string]::IsNullOrEmpty($Request.players)) { $Exception = [Exception]::new("SteamID $SteamID64 couldn't be found.") $ErrorRecord = [System.Management.Automation.ErrorRecord]::new( $Exception, 'PlayerNotFound', [System.Management.Automation.ErrorCategory]::ObjectNotFound, $Request ) $PSCmdlet.WriteError($ErrorRecord) } } # Process end { Write-Verbose -Message "[END ] Ending: $($MyInvocation.MyCommand)" } } # Cmdlet #EndRegion '.\Public\API\Get-SteamPlayerBan.ps1' 84 #Region '.\Public\API\Get-SteamPlayerSummary.ps1' 0 function Get-SteamPlayerSummary { <# .SYNOPSIS Fetches basic profile information for a list of 64-bit Steam IDs. .DESCRIPTION Fetches basic profile information from the Steam Community. .PARAMETER SteamID64 Specifies a comma-separated list of 64-bit Steam IDs to fetch profile information for. Up to 100 Steam IDs can be requested. .EXAMPLE Get-SteamPlayerSummary -SteamID64 76561197960435530, 76561197960434622 This example fetches profile information for the players with the specified Steam IDs. .INPUTS int64[]: Specifies an array of 64-bit integers representing Steam IDs. .OUTPUTS Returns a custom object with the properties listed below. Some data associated with a Steam account may be hidden if the user has their profile visibility set to "Friends Only" or "Private". In that case, only public data will be returned. Public Data - steamid: 64-bit SteamID of the user. - personaname: The player's persona name (display name). - profileurl: The full URL of the player's Steam Community profile. - avatar: The full URL of the player's 32x32px avatar. If the user hasn't configured an avatar, this will be the default ? avatar. - avatarmedium: The full URL of the player's 64x64px avatar. If the user hasn't configured an avatar, this will be the default ? avatar. - avatarfull: The full URL of the player's 184x184px avatar. If the user hasn't configured an avatar, this will be the default ? avatar. - personastate: The user's current status. 0 - Offline, 1 - Online, 2 - Busy, 3 - Away, 4 - Snooze, 5 - looking to trade, 6 - looking to play. If the player's profile is private, this will always be "0", except if the user has set their status to looking to trade or looking to play, because a bug makes those status appear even if the profile is private. - communityvisibilitystate: This represents whether the profile is visible or not, and if it is visible, why you are allowed to see it. Note that because this WebAPI does not use authentication, there are only two possible values returned: 1 - the profile is not visible to you (Private, Friends Only, etc), 3 - the profile is "Public", and the data is visible. Mike Blaszczak's post on Steam forums says, "The community visibility state this API returns is different than the privacy state. It's the effective visibility state from the account making the request to the account being viewed given the requesting account's relationship to the viewed account." - profilestate: If set, indicates the user has a community profile configured (will be set to '1') - lastlogoff: The last time the user was online, in unix time. Only available when you are friends with the requested user (since Feb, 4). - commentpermission: If set, indicates the profile allows public comments. Private Data - realname: The player's "Real Name", if they have set it. - primaryclanid: The player's primary group, as configured in their Steam Community profile. - timecreated: The time the player's account was created. - gameid: If the user is currently in-game, this value will be returned and set to the gameid of that game. - gameserverip: The ip and port of the game server the user is currently playing on, if they are playing on-line in a game using Steam matchmaking. Otherwise will be set to "0.0.0.0:0". - gameextrainfo: If the user is currently in-game, this will be the name of the game they are playing. This may be the name of a non-Steam game shortcut. - cityid: This value will be removed in a future update (see loccityid) - loccountrycode: If set on the user's Steam Community profile, The user's country of residence, 2-character ISO country code - locstatecode: If set on the user's Steam Community profile, The user's state of residence - loccityid: An internal code indicating the user's city of residence. A future update will provide this data in a more useful way. steam_location gem/package makes player location data readable for output. .NOTES Author: Frederik Hjorslev Nylander .LINK https://hjorslev.github.io/SteamPS/Get-SteamPlayerSummary.html #> [CmdletBinding()] param ( [Parameter(Mandatory = $true, HelpMessage = '64 bit Steam ID to return player summary for.', ValueFromPipelineByPropertyName = $true)] [int64[]]$SteamID64 ) begin { Write-Verbose -Message "[BEGIN ] Starting: $($MyInvocation.MyCommand)" } process { $Request = Invoke-RestMethod -Uri 'https://api.steampowered.com/ISteamUser/GetPlayerSummaries/v2' -UseBasicParsing -Body @{ key = Get-SteamAPIKey steamids = ($SteamID64 -join ',') } if ($Request.response.players) { foreach ($Item in $Request.response.players) { [PSCustomObject]@{ SteamID64 = $Item.steamid PersonaName = $Item.personaname ProfileUrl = $Item.profileurl Avatar = $Item.avatar AvatarMedium = $Item.avatarmedium AvatarFull = $Item.avatarfull AvatarHash = $Item.avatarhash PersonaState = [PersonaState]$Item.personastate CommunityVisibilityState = [CommunityVisibilityState]$Item.communityvisibilitystate ProfileState = $Item.profilestate LastLogOff = ((Get-Date "01.01.1970") + ([System.TimeSpan]::FromSeconds($Item.lastlogoff))).ToString("yyyy-MM-dd HH:mm:ss") CommentPermission = $Item.commentpermission RealName = $Item.realname PrimaryClanID = $Item.primaryclanid TimeCreated = ((Get-Date "01.01.1970") + ([System.TimeSpan]::FromSeconds($Item.timecreated))).ToString("yyyy-MM-dd HH:mm:ss") AppID = $Item.gameid GameServerIP = [ipaddress]$Item.gameserverip GameExtraInfo = $Item.gameextrainfo PersonaStateFlags = $Item.personastateflags LocCountryCode = $Item.loccountrycode LocStateCode = $Item.locstatecode LocCityID = $Item.loccityid } } } elseif ($Request.response.players.Length -eq 0) { $Exception = [Exception]::new("SteamID $SteamID64 couldn't be found.") $ErrorRecord = [System.Management.Automation.ErrorRecord]::new( $Exception, 'NoPlayerFound', [System.Management.Automation.ErrorCategory]::ObjectNotFound, $Request ) $PSCmdlet.WriteError($ErrorRecord) } } # Process end { Write-Verbose -Message "[END ] Ending: $($MyInvocation.MyCommand)" } } #EndRegion '.\Public\API\Get-SteamPlayerSummary.ps1' 118 #Region '.\Public\API\Resolve-VanityURL.ps1' 0 function Resolve-VanityURL { <# .SYNOPSIS Retrieves the SteamID64 linked to a specified vanity URL (custom URL) from the Steam Community. .DESCRIPTION Using the Steam Web API, this cmdlet fetches the SteamID64 that corresponds to a provided vanity URL (custom URL) from the Steam Community. .PARAMETER VanityURL This parameter specifies the vanity URL (custom URL) for which the SteamID64 is to be retrieved. .PARAMETER UrlType This parameter defines the type of vanity URL. The valid values are: 1 (default) for an individual profile, 2 for a group, and 3 for an official game group. .EXAMPLE Resolve-VanityURL -VanityURL user This example retrieves the SteamID64 linked to the vanity URL 'user'. .EXAMPLE Resolve-VanityURL -VanityURL user1, user2 This example retrieves the SteamID64s linked to the vanity URLs 'user1' and 'user2'. .INPUTS The VanityURL parameter accepts string input. .OUTPUTS The cmdlet returns a custom object containing the VanityURL and its associated SteamID64. .NOTES Author: Frederik Hjorslev Nylander .LINK https://hjorslev.github.io/SteamPS/Resolve-VanityURL.html #> [CmdletBinding()] param ( [Parameter(Mandatory = $true, HelpMessage = 'Enter the vanity URL (custom URL) for which the SteamID64 is to be retrieved.')] [ValidateScript( { if (([System.URI]$_ ).IsAbsoluteUri -eq $true) { throw "Do not enter the fully qualified URL, but just the ID (e.g.) everything after https://steamcommunity.com/id/" } $true })] [string[]]$VanityURL, [Parameter(Mandatory = $false, HelpMessage = 'The type of vanity URL. 1 (default): Individual profile, 2: Group, 3: Official game group.')] [ValidateSet(1, 2, 3)] [int]$UrlType = 1 ) begin { Write-Verbose -Message "[BEGIN ] Starting: $($MyInvocation.MyCommand)" } process { foreach ($Item in $VanityURL) { $Request = Invoke-RestMethod -Uri 'https://api.steampowered.com/ISteamUser/ResolveVanityURL/v1/' -UseBasicParsing -Body @{ key = Get-SteamAPIKey vanityurl = $Item url_type = $UrlType } if ($Request.response.success -eq '1') { [PSCustomObject]@{ 'VanityURL' = $Item 'SteamID64' = ([int64]$Request.response.steamid) } } elseif ($Request.response.success -eq '42') { $Exception = [Exception]::new("Unable to find $Item.") $ErrorRecord = [System.Management.Automation.ErrorRecord]::new( $Exception, "VanityURLNotFound", [System.Management.Automation.ErrorCategory]::ObjectNotFound, $Request.response.success ) $PSCmdlet.WriteError($ErrorRecord) } } } # Process end { Write-Verbose -Message "[END ] Ending: $($MyInvocation.MyCommand)" } } # Cmdlet #EndRegion '.\Public\API\Resolve-VanityURL.ps1' 89 #Region '.\Public\Server\Get-SteamServerInfo.ps1' 0 function Get-SteamServerInfo { <# .SYNOPSIS Query a running steam based game server. .DESCRIPTION The cmdlet fetches server information from a running game server using UDP/IP packets. It will return information ServerName, Map, InstallDir, GameName, AppID, Players MaxPlayers, Bots, ServerType, Environment, Visibility, VAC andVersion. .PARAMETER IPAddress Enter the IP address of the Steam based server. .PARAMETER Port Enter the port number of the Steam based server. .PARAMETER Timeout Timeout in milliseconds before giving up querying the server. .EXAMPLE Get-SteamServerInfo -IPAddress '185.15.73.207' -Port 27015 ``` Protocol : 17 ServerName : SAS Proving Ground 10 (EU) Map : TH-SmallTown InstallDir : groundbranch GameName : Ground Branch AppID : 16900 Players : 6 MaxPlayers : 10 Bots : 0 ServerType : Dedicated Environment : Windows Visibility : Public VAC : Unsecured Version : 1.0.0.0 ExtraDataFlag : 177 IPAddress : 185.15.73.207 Port : 27015 ``` .NOTES Author: Jordan Borean, Chris Dent and Frederik Hjorslev Nylander .LINK https://hjorslev.github.io/SteamPS/Get-SteamServerInfo.html #> [CmdletBinding()] param ( [Parameter(Mandatory = $true, HelpMessage = 'Enter the IP address of the Steam based server.')] [System.Net.IPAddress]$IPAddress, [Parameter(Mandatory = $true, HelpMessage = 'Enter the port number of the Steam based server.')] [int]$Port, [Parameter(Mandatory = $false, HelpMessage = 'Timeout in milliseconds before giving up querying the server.')] [int]$Timeout = 5000 ) begin { # A2S_INFO: Retrieves information about the server including, but not limited to: its name, the map currently being played, and the number of players. # https://developer.valvesoftware.com/wiki/Server_queries#A2S_INFO $A2S_INFO = [byte]0xFF, 0xFF, 0xFF, 0xFF, 0x54, 0x53, 0x6F, 0x75, 0x72, 0x63, 0x65, 0x20, 0x45, 0x6E, 0x67, 0x69, 0x6E, 0x65, 0x20, 0x51, 0x75, 0x65, 0x72, 0x79, 0x00 } process { try { # Instantiate client and endpoint $Client = New-Object -TypeName Net.Sockets.UDPClient(0) [void]$Client.Send($A2S_INFO, $A2S_INFO.Length, $IPAddress, $Port) $Client.Client.SendTimeout = $Timeout $Client.Client.ReceiveTimeout = $Timeout $IPEndpoint = New-Object -TypeName Net.IPEndpoint([Net.IPAddress]::Any, 0) # The first 4 bytes are 255 which seems to be some sort of header. $ReceivedData = $Client.Receive([Ref]$IPEndpoint) | Select-Object -Skip 4 $Stream = [System.IO.BinaryReader][System.IO.MemoryStream][Byte[]]$ReceivedData # Challenge: if ($Stream.ReadByte() -eq 65) { # If the response is a challenge, resend query with last 4 bytes of the challenge $challenge = while ($Stream.BaseStream.Position -lt $Stream.BaseStream.Length) { $Stream.ReadByte() } $newQuery = $A2S_INFO + $challenge [void]$Client.Send($newQuery, $newQuery.Length, $IPAddress, $Port) # The first 4 bytes are 255 which seems to be some sort of header. $ReceivedData = $Client.Receive([Ref]$IPEndpoint) | Select-Object -Skip 4 $Stream = [System.IO.BinaryReader][System.IO.MemoryStream][Byte[]]$ReceivedData } else { $Stream.BaseStream.Position = 0 } $Client.Close() } catch { $Exception = [Exception]::new("Could not reach server {0}:{1}.") -f $IPAddress, $Port $ErrorRecord = [System.Management.Automation.ErrorRecord]::new( $Exception, "ServerNotFound", [System.Management.Automation.ErrorCategory]::ConnectionError, $ReceivedData ) $PSCmdlet.WriteError($ErrorRecord) } # If we cannot reach the server we will not display the empty object. if ($Stream) { # This is also a header - that will always be equal to 'I' (0x49). $Stream.ReadByte() | Out-Null [PSCustomObject]@{ Protocol = [int]$Stream.ReadByte() ServerName = Get-PacketString -Stream $Stream Map = Get-PacketString -Stream $Stream InstallDir = Get-PacketString -Stream $Stream GameName = Get-PacketString -Stream $Stream AppID = [int]$Stream.ReadUInt16() Players = [int]$Stream.ReadByte() MaxPlayers = [int]$Stream.ReadByte() Bots = $Stream.ReadByte() ServerType = [ServerType]$Stream.ReadByte() Environment = [OSType]$Stream.ReadByte() Visibility = [Visibility]$Stream.ReadByte() VAC = [VAC]$Stream.ReadByte() Version = Get-PacketString -Stream $Stream ExtraDataFlag = $Stream.ReadByte() IPAddress = $IPAddress Port = $Port } # PSCustomObject } } # Process } # Cmdlet #EndRegion '.\Public\Server\Get-SteamServerInfo.ps1' 138 #Region '.\Public\Server\Install-SteamCMD.ps1' 0 function Install-SteamCMD { <# .SYNOPSIS Install SteamCMD. .DESCRIPTION This cmdlet downloads SteamCMD and configures it in a custom or predefined location (C:\Program Files\SteamCMD). .PARAMETER InstallPath Specify the install location of SteamCMD. .PARAMETER Force The Force parameter allows the user to skip the "Should Continue" box. .EXAMPLE Install-SteamCMD Installs SteamCMD in C:\Program Files\SteamCMD. .EXAMPLE Install-SteamCMD -InstallPath 'C:' Installs SteamCMD in C:\SteamCMD. .NOTES Author: Frederik Hjorslev Nylander .LINK https://hjorslev.github.io/SteamPS/Install-SteamCMD.html #> [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium')] param ( [Parameter(Mandatory = $false)] [ValidateScript( { if ($_.Substring(($_.Length -1)) -eq '\') { throw "InstallPath may not end with a trailing slash." } $true })] [string]$InstallPath = "$env:ProgramFiles", [Parameter(Mandatory = $false)] [switch]$Force ) begin { $isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator") if ($isAdmin -eq $false) { $Exception = [Exception]::new('The current PowerShell session is not running as Administrator. Start PowerShell by using the Run as Administrator option, and then try running the script again.') $ErrorRecord = [System.Management.Automation.ErrorRecord]::new( $Exception, 'MissingUserPermissions', [System.Management.Automation.ErrorCategory]::PermissionDenied, $isAdmin ) $PSCmdlet.ThrowTerminatingError($ErrorRecord) } } process { if ($Force -or $PSCmdlet.ShouldContinue('Would you like to continue?', 'Install SteamCMD')) { # Ensures that SteamCMD is installed in a folder named SteamCMD. $InstallPath = $InstallPath + '\SteamCMD' if (-not ((Get-SteamPath).Path -eq $InstallPath)) { Write-Verbose -Message "Adding $InstallPath to Environment Variable PATH." Add-EnvPath -Path $InstallPath -Container Machine } else { Write-Verbose -Message "Path $((Get-SteamPath).Path) already exists." } $TempDirectory = 'C:\Temp' if (-not (Test-Path -Path $TempDirectory)) { Write-Verbose -Message 'Creating Temp directory.' New-Item -Path 'C:\' -Name 'Temp' -ItemType Directory | Write-Verbose } # Download SteamCMD. Invoke-WebRequest -Uri 'https://steamcdn-a.akamaihd.net/client/installer/steamcmd.zip' -OutFile "$TempDirectory\steamcmd.zip" -UseBasicParsing # Create SteamCMD directory if necessary. if (-not (Test-Path -Path $InstallPath)) { Write-Verbose -Message "Creating SteamCMD directory: $InstallPath" New-Item -Path $InstallPath -ItemType Directory | Write-Verbose Expand-Archive -Path "$TempDirectory\steamcmd.zip" -DestinationPath $InstallPath } # Doing some initial configuration of SteamCMD. The first time SteamCMD is launched it will need to do some updates. Write-Host -Object 'Configuring SteamCMD for the first time. This might take a little while.' Write-Host -Object 'Please wait' -NoNewline Start-Process -FilePath "$InstallPath\steamcmd.exe" -ArgumentList 'validate +quit' -WindowStyle Hidden do { Write-Host -Object "." -NoNewline Start-Sleep -Seconds 3 } until (-not (Get-Process -Name "*steamcmd*")) } } # Process end { if (Test-Path -Path "$TempDirectory\steamcmd.zip") { Remove-Item -Path "$TempDirectory\steamcmd.zip" -Force } if (Test-Path -Path (Get-SteamPath).Executable) { Write-Output -InputObject "SteamCMD is now installed. Please close/open your PowerShell host." } } # End } # Cmdlet #EndRegion '.\Public\Server\Install-SteamCMD.ps1' 113 #Region '.\Public\Server\Update-SteamApp.ps1' 0 function Update-SteamApp { <# .SYNOPSIS Install or update a Steam application using SteamCMD. .DESCRIPTION Install or update a Steam application using SteamCMD. If SteamCMD is missing, it will be installed first. You can either search for the application by name or enter the specific Application ID. .PARAMETER ApplicationName Enter the name of the app to make a wildcard search for the application. .PARAMETER ApplicationID Enter the application ID you wish to install. .PARAMETER Credential If the app requires login to install or update, enter your Steam username and password. .PARAMETER Path Path to installation folder. .PARAMETER Arguments Enter any additional arguments here. Beware, the following arguments are already used: If you use Steam login to install/upload the app the following arguments are already used: "+force_install_dir $Path +login $SteamUserName $SteamPassword +app_update $SteamAppID $Arguments +quit" If you use anonymous login to install/upload the app the following arguments are already used: "+force_install_dir $Path +login anonymous +app_update $SteamAppID $Arguments +quit" .PARAMETER Force The Force parameter allows the user to skip the "Should Continue" box. .EXAMPLE Update-SteamApp -ApplicationName 'Arma 3' -Credential 'Toby' -Path 'C:\DedicatedServers\Arma3' Because there are multiple hits when searching for Arma 3, the user will be promoted to select the right application. .EXAMPLE Update-SteamApp -AppID 376030 -Path 'C:\DedicatedServers\ARK-SurvivalEvolved' Here we use anonymous login because the particular application (ARK: Survival Evolved Dedicated Server) doesn't require login. .NOTES Author: Frederik Hjorslev Nylander SteamCMD CLI parameters: https://developer.valvesoftware.com/wiki/Command_Line_Options#Command-line_parameters_4 .LINK https://hjorslev.github.io/SteamPS/Update-SteamApp.html #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSShouldProcess', '', Justification='Is implemented but not accepted by PSSA.')] [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium' )] param ( [Parameter(Position = 0, Mandatory = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ApplicationName' )] [Alias('GameName')] [string]$ApplicationName, [Parameter(Position = 0, Mandatory = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ApplicationID' )] [ValidateScript({ if ($null -eq (Get-SteamApp -ApplicationID $_)) { throw "ApplicationID $_ couldn't be found." } $true })] [Alias('AppID')] [int]$ApplicationID, [Parameter(Mandatory = $true)] [ValidateScript( { if ($_.Substring(($_.Length -1)) -eq '\') { throw "Path may not end with a trailing slash." } $true })] [string]$Path, [Parameter(Mandatory = $false)] [ValidateNotNull()] [System.Management.Automation.PSCredential] [System.Management.Automation.Credential()] $Credential = [System.Management.Automation.PSCredential]::Empty, [Parameter(Mandatory = $false)] [string]$Arguments, [Parameter(Mandatory = $false)] [switch]$Force ) begin { if ($null -eq (Get-SteamPath)) { throw 'SteamCMD could not be found in the env:Path. Have you executed Install-SteamCMD?' } # Install SteamCMD if it is missing. if (-not (Test-Path -Path (Get-SteamPath).Executable)) { Start-Process powershell -ArgumentList '-NoExit -Command "Install-SteamCMD; exit"' -Verb RunAs Write-Verbose -Message 'Installing SteamCMD in another window. Please wait and try again.' throw "SteamCMD is missing and is being installed in another window. Please wait until the other window closes, restart your console, and try again." } } # Begin process { function Use-SteamCMD ($SteamAppID) { # If Steam username and Steam password are not empty we use them for logging in. if ($null -ne $Credential.UserName) { Write-Verbose -Message "Logging into Steam as $($Credential | Select-Object -ExpandProperty UserName)." $SteamCMDProcess = Start-Process -FilePath (Get-SteamPath).Executable -NoNewWindow -ArgumentList "+force_install_dir `"$Path`" +login $($Credential.UserName) $($Credential.GetNetworkCredential().Password) +app_update $SteamAppID $Arguments +quit" -Wait -PassThru if ($SteamCMDProcess.ExitCode -ne 0) { Write-Error -Message ("SteamCMD closed with ExitCode {0}" -f $SteamCMDProcess.ExitCode) -Category CloseError } } # If Steam username and Steam password are empty we use anonymous login. elseif ($null -eq $Credential.UserName) { Write-Verbose -Message 'Using SteamCMD as anonymous.' $SteamCMDProcess = Start-Process -FilePath (Get-SteamPath).Executable -NoNewWindow -ArgumentList "+force_install_dir `"$Path`" +login anonymous +app_update $SteamAppID $Arguments +quit" -Wait -PassThru if ($SteamCMDProcess.ExitCode -ne 0) { Write-Error -Message ("SteamCMD closed with ExitCode {0}" -f $SteamCMDProcess.ExitCode) -Category CloseError } } } # If game is found by searching for game name. if ($PSCmdlet.ParameterSetName -eq 'ApplicationName') { try { $SteamApp = Get-SteamApp -ApplicationName $ApplicationName # Install selected Steam application if a SteamAppID has been selected. if (-not ($null -eq $SteamApp)) { if ($Force -or $PSCmdlet.ShouldContinue("Do you want to install or update $($SteamApp.ApplicationName)?", "Update SteamApp $($SteamApp.ApplicationName)?")) { Write-Verbose -Message "The application $($SteamApp.ApplicationName) is being updated. Please wait for SteamCMD to finish." Use-SteamCMD -SteamAppID $SteamApp.ApplicationID } # Should Continue } } catch { Throw "$ApplicationName couldn't be updated." } } # ParameterSet ApplicationName # If game is found by using a unique ApplicationID. if ($PSCmdlet.ParameterSetName -eq 'ApplicationID') { try { $SteamAppID = $ApplicationID # Install selected Steam application. if ($Force -or $PSCmdlet.ShouldContinue("Do you want to install or update $($SteamAppID)?", "Update SteamApp $($SteamAppID)?")) { Write-Verbose -Message "The application with AppID $SteamAppID is being updated. Please wait for SteamCMD to finish." Use-SteamCMD -SteamAppID $SteamAppID } # Should Continue } catch { Throw "$SteamAppID couldn't be updated." } } # ParameterSet AppID } # Process } # Cmdlet #EndRegion '.\Public\Server\Update-SteamApp.ps1' 166 #Region '.\Public\Server\Update-SteamServer.ps1' 0 function Update-SteamServer { <# .SYNOPSIS Update a Steam based game server. .DESCRIPTION This cmdlet presents a workflow to keep a steam based game server up to date. The server is expecting the game server to be running as a Windows Service. .PARAMETER AppID Enter the application ID you wish to install. .PARAMETER ServiceName Specify the Windows Service Name. You can get a list of services with Get-Service. .PARAMETER IPAddress Enter the IP address of the Steam based server. .PARAMETER Port Enter the port number of the Steam based server. .PARAMETER Path Install location of the game server. .PARAMETER Credential If the app requires login to install or update, enter your Steam username and password. .PARAMETER Arguments Enter any additional arguments here. .PARAMETER LogPath Specify the directory of the log files. .PARAMETER DiscordWebhookUri Enter a Discord Webhook Uri if you wish to get notifications about the server update. .PARAMETER AlwaysNotify Always receive a notification when a server has been updated. Default is only to send on errors. .PARAMETER TimeoutLimit Number of times the cmdlet checks if the server is online or offline. When the limit is reached an error is thrown. .EXAMPLE Update-SteamServer -AppID 476400 -ServiceName GB-PG10 -IPAddress '185.15.73.207' -Port 27015 .NOTES Author: Frederik Hjorslev Nylander .LINK https://hjorslev.github.io/SteamPS/Update-SteamServer.html #> # TODO: Implement support for ShouldContinue. Due to compatibility we wait with this. [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSShouldProcess', '')] [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'High')] param ( [Parameter(Mandatory = $true)] [int]$AppID, [Parameter(Mandatory = $true)] [ValidateScript( { Get-Service -Name $_ })] [string]$ServiceName, [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [System.Net.IPAddress]$IPAddress, [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [int]$Port, [Parameter(Mandatory = $false)] [Alias('ApplicationPath')] [string]$Path = "C:\DedicatedServers\$ServiceName", [Parameter(Mandatory = $false)] [ValidateNotNull()] [System.Management.Automation.PSCredential] [System.Management.Automation.Credential()] $Credential = [System.Management.Automation.PSCredential]::Empty, [Parameter(Mandatory = $false)] [string]$Arguments, [Parameter(Mandatory = $false)] [Alias('LogLocation')] [string]$LogPath = 'C:\DedicatedServers\Logs', [Parameter(Mandatory = $false)] [string]$DiscordWebhookUri, [Parameter(Mandatory = $false)] [string]$AlwaysNotify, [Parameter(Mandatory = $false)] [int]$TimeoutLimit = 10 ) begin { if ($null -eq (Get-SteamPath)) { $Exception = [Exception]::new('SteamCMD could not be found in the env:Path. Have you executed Install-SteamCMD?') $ErrorRecord = [System.Management.Automation.ErrorRecord]::new( $Exception, 'SteamCMDNotInstalled', [System.Management.Automation.ErrorCategory]::NotInstalled, (Test-Admin) ) $PSCmdlet.ThrowTerminatingError($ErrorRecord) } if ((Test-Admin) -eq $false) { $Exception = [Exception]::new('The current PowerShell session is not running as Administrator. Start PowerShell by using the Run as Administrator option, and then try running the script again.') $ErrorRecord = [System.Management.Automation.ErrorRecord]::new( $Exception, 'MissingUserPermissions', [System.Management.Automation.ErrorCategory]::PermissionDenied, (Test-Admin) ) $PSCmdlet.ThrowTerminatingError($ErrorRecord) } # Log settings $PSFLoggingProvider = @{ Name = 'logfile' InstanceName = "Update game server $ServiceName" FilePath = "$LogPath\$ServiceName\$ServiceName-%Date%.csv" Enabled = $true LogRotatePath = "$LogPath\$ServiceName\$ServiceName-*.csv" } Set-PSFLoggingProvider @PSFLoggingProvider # Variable that stores how many times the cmdlet has checked whether the # server is offline or online. $TimeoutCounter = 0 } process { # Get server status and output it. $ServerStatus = Get-SteamServerInfo -IPAddress $IPAddress -Port $Port -ErrorAction SilentlyContinue # If server is alive we check it is empty before updating it. if ($ServerStatus) { Write-PSFMessage -Level Host -Message $ServerStatus -Tag 'ServerStatus' -ModuleName 'SteamPS' -Target "$($IPAddress):$($Port)" # Waiting to server is empty. Checking every 60 seconds. while ($ServerStatus.Players -ne 0) { Write-PSFMessage -Level Host -Message 'Awaiting that the server is empty before updating.' -Tag 'ServerStatus' -ModuleName 'SteamPS' -Target "$($IPAddress):$($Port)" $ServerStatus = Get-SteamServerInfo -IPAddress $IPAddress -Port $Port -ErrorAction SilentlyContinue Write-PSFMessage -Level Host -Message $($ServerStatus | Select-Object -Property ServerName, Port, Players) -Tag 'ServerStatus' -ModuleName 'SteamPS' -Target "$($IPAddress):$($Port)" Start-Sleep -Seconds 60 } # Server is now empty and we stop, update and start the server. Write-PSFMessage -Level Host -Message "Stopping $ServiceName..." -Tag 'ServerUpdate' -ModuleName 'SteamPS' -Target $ServiceName Stop-Service -Name $ServiceName Write-PSFMessage -Level Host -Message "$($ServiceName): $((Get-Service -Name $ServiceName).Status)." -Tag 'ServerUpdate' -ModuleName 'SteamPS' -Target $ServiceName } else { Write-PSFMessage -Level Host -Message 'Server could not be reached.' -Tag 'ServerStatus' -ModuleName 'SteamPS' -Target "$($IPAddress):$($Port)" Write-PSFMessage -Level Host -Message 'Continuing with updating server.' -Tag 'ServerUpdate' -ModuleName 'SteamPS' -Target "$($IPAddress):$($Port)" } Write-PSFMessage -Level Host -Message "Updating $ServiceName..." -Tag 'ServerUpdate' -ModuleName 'SteamPS' -Target $ServiceName if ($null -ne $Credential) { Update-SteamApp -AppID $AppID -Path $Path -Credential $Credential -Arguments "$Arguments" -Force } else { Update-SteamApp -AppID $AppID -Path $Path -Arguments "$Arguments" -Force } Write-PSFMessage -Level Host -Message "Starting $ServiceName" -Tag 'ServerUpdate' -ModuleName 'SteamPS' -Target $ServiceName Start-Service -Name $ServiceName Write-PSFMessage -Level Host -Message "$($ServiceName): $((Get-Service -Name $ServiceName).Status)." -Tag 'ServerUpdate' -ModuleName 'SteamPS' -Target $ServiceName do { $TimeoutCounter++ # Add +1 for every loop. Write-PSFMessage -Level Host -Message 'Waiting for server to come online again.' -Tag 'ServerStatus' -ModuleName 'SteamPS' -Target "$($IPAddress):$($Port)" Start-Sleep -Seconds 60 # Getting new server information. $ServerStatus = Get-SteamServerInfo -IPAddress $IPAddress -Port $Port -ErrorAction SilentlyContinue | Select-Object -Property ServerName, Port, Players Write-PSFMessage -Level Host -Message $ServerStatus -Tag 'ServerStatus' -ModuleName 'SteamPS' -Target "$($IPAddress):$($Port)" Write-PSFMessage -Level Host -Message "No response from $($IPAddress):$($Port)." -Tag 'ServerStatus' -ModuleName 'SteamPS' -Target "$($IPAddress):$($Port)" Write-PSFMessage -Level Host -Message "TimeoutCounter: $TimeoutCounter/$TimeoutLimit" -Tag 'ServerStatus' -ModuleName 'SteamPS' -Target "$($IPAddress):$($Port)" if ($TimeoutCounter -ge $TimeoutLimit) { break } } until ($null -ne $ServerStatus.ServerName) if ($null -ne $ServerStatus.ServerName) { Write-PSFMessage -Level Host -Message "$($ServerStatus.ServerName) is now ONLINE." -Tag 'ServerStatus' -ModuleName 'SteamPS' -Target "$($IPAddress):$($Port)" $ServerState = 'ONLINE' $Color = 'Green' } else { Write-PSFMessage -Level Critical -Message "Server seems to be OFFLINE after the update..." -Tag 'ServerStatus' -ModuleName 'SteamPS' -Target "$($IPAddress):$($Port)" $ServerState = 'OFFLINE' $Color = 'Red' } } # Process end { if ($null -ne $DiscordWebhookUri -and ($ServerState -eq 'OFFLINE' -or $AlwaysNotify -eq $true)) { # Send Message to Discord about the update. $ServerFact = New-DiscordFact -Name 'Game Server Info' -Value $(Get-SteamServerInfo -IPAddress $IPAddress -Port $Port -ErrorAction SilentlyContinue | Select-Object -Property ServerName, IP, Port, Players | Out-String) $ServerStateFact = New-DiscordFact -Name 'Server State' -Value $(Write-Output -InputObject "Server is $ServerState!") $LogFact = New-DiscordFact -Name 'Log Location' -Value "$LogPath\$ServiceName\$ServiceName-%Date%.csv" $Section = New-DiscordSection -Title "$ServiceName - Update Script Executed" -Facts $ServerStateFact, $ServerFact, $LogFact -Color $Color Send-DiscordMessage -WebHookUrl $DiscordWebhookUri -Sections $Section } } # End } # Cmdlet #EndRegion '.\Public\Server\Update-SteamServer.ps1' 213 |