Category Archives: Powershell

Powershell things

Chivalry 2 Listplayers Organizer

This program provides a user-friendly graphical interface for organizing player data from Chivalry 2. It streamlines the process of managing player information, tracking nickname changes, and prioritizing specific players for closer monitoring.

Key Features:

  • Graphical User Interface: The script operates within a GUI, making it more accessible and user-friendly. The interface includes buttons for processing data, loading pinned players, and saving changes, as well as text boxes for displaying and editing pinned players.
  • Updating the Player Database: Automatically updates or creates a new file named Chivalry2PlayersDatabase.log. It organizes players by their PlayFabPlayerIds and associated nicknames and last updated time in a clear and structured format.
  • Tracking Nickname Changes: Maintains a historical record of nicknames for each PlayFabPlayerId, enabling users to track changes in player nicknames over time.
  • Prioritizing Pinned Players: Players listed in Chivalry2PinnedPlayers.log are given priority and placed at the top of Chivalry2PlayersDatabase.log, marked with a “*Pinned Player” indicator. This is particularly useful for tracking key players.
  • Real-Time Clipboard Processing: The “Process ListPlayers” button enables users to process player data directly from the clipboard, eliminating the need for manual file management. This feature is designed for efficiency and ease of use, especially during active gaming sessions.

Usage Instructions:

Main GUI Window
1. In a Chivalry 2 Server, open Console by pressing tilde key, type “listplayers” and then press enter key
2. Click “Process ListPlayers” button on the window to get organized data
3. Put PlayFabPlayerIds to the right textbox(1 PlayFabPlayerId per a line) then click “Save Pinned Players”
4. With listplayers in your clipboard, click “Process ListPlayers” Button again and you will see Pinned Players on top
Players with multiple nickname records

Changes in version 1.36

  • Better handle of player nicknames.
  • While processing, Process button becomes disabled.

PowerShell
# By vintertid from Discord

Add-Type -AssemblyName PresentationFramework

Add-Type -Name Window -Namespace Console -MemberDefinition '
[DllImport("Kernel32.dll")]
public static extern IntPtr GetConsoleWindow();

[DllImport("user32.dll")]
public static extern bool ShowWindow(IntPtr hWnd, Int32 nCmdShow);
'

$consoleWindow = [Console.Window]::GetConsoleWindow()
[Console.Window]::ShowWindow($consoleWindow, 0)

function Process-ListPlayers {
    $currentTime = Get-Date -Format "yyyy-MM-dd-HH:mm:ss UTCK"
    Add-Type -AssemblyName System.Windows.Forms
    $content = [System.Windows.Forms.Clipboard]::GetText()
	
    $listplayersDir = ".\listplayers"
    if (-not (Test-Path $listplayersDir)) {
        New-Item -Path $listplayersDir -ItemType Directory
    }
	
    $filename = "listplayers_" + (Get-Date -Format "yyyy-MM-dd-HH-mm-ss") + ".log"
    $filepath = Join-Path $listplayersDir $filename
	
    if ($content -match "^ServerName - .*\r?\nName -  PlayFabPlayerId - EOSPlayerId - Score - Kills - Deaths - Ping\r?\n(.+\r?\n)+") {
        Set-Content -Path $filepath -Value $content -Encoding UTF8
    } else {
        return
    }

    if (-not $content -match '\b[A-F0-9]{10,16}\b') { return }
    $players = $content -split "\r?\n" | Where-Object { $_ -match '^.+ - \b[A-F0-9]{10,16}\b - ' }
    if (-not $players) { return }
    $existingPlayers = @{}
    $updatedPlayerIds = @()
    $pinnedPlayers = @()

    if (Test-Path .\Chivalry2PinnedPlayers.log) {
        $pinnedPlayers = Get-Content -Path .\Chivalry2PinnedPlayers.log -Encoding UTF8
    }

    if (Test-Path .\Chivalry2PlayersDatabase.log) {
        $existingContent = Get-Content -Path .\Chivalry2PlayersDatabase.log -Encoding UTF8
        $currentId = $null
        foreach ($line in $existingContent) {
            if ($line -match '^\*Pinned Player$') {
                $isPinned = $true
                continue
            }
            if ($line -match '^[\w-]{13,16}$') {
                $currentId = $line
                $existingPlayers[$currentId] = @{ 'Nicknames' = @(); 'IsPinned' = $isPinned; 'TimeData' = 'no-time-data-old-version' }
                $isPinned = $false
            } elseif ($line -match 'listplayered (.+)$') {
                $existingPlayers[$currentId]['TimeData'] = $matches[1]
            } elseif ($line -match '^\s+-\s+(.*)') {
                if (-not $existingPlayers[$currentId]['Nicknames'].Contains($matches[1])) {
                    $existingPlayers[$currentId]['Nicknames'] += $matches[1]
                }
            }
        }
    }

    foreach ($player in $players) {
        if ($player -match '^(?<Nickname>.+?)\s+-\s+(?<PlayFabPlayerId>[A-F0-9]{10,16})\s+-') {
            $Nickname = $matches['Nickname'].Trim()
            $PlayFabPlayerId = $matches['PlayFabPlayerId'].Trim()

            if ($PlayFabPlayerId -and $existingPlayers.ContainsKey($PlayFabPlayerId)) {
                if (-not $existingPlayers[$PlayFabPlayerId]['Nicknames'].Contains($Nickname)) {
                    $existingPlayers[$PlayFabPlayerId]['Nicknames'] += $Nickname
                }
                $existingPlayers[$PlayFabPlayerId]['TimeData'] = $currentTime
            } elseif ($PlayFabPlayerId) {
                $existingPlayers[$PlayFabPlayerId] = @{ 'Nicknames' = @($Nickname); 'IsPinned' = $false; 'TimeData' = $currentTime }
            }
            $updatedPlayerIds += $PlayFabPlayerId
        }
    }

    foreach ($existingPlayer in $existingPlayers.Keys) {
        if ($existingPlayers[$existingPlayer]['IsPinned'] -and $pinnedPlayers -notcontains $existingPlayer) {
            $existingPlayers[$existingPlayer]['IsPinned'] = $false
        }
    }

    foreach ($id in $pinnedPlayers) {
        if ($id -and $existingPlayers.ContainsKey($id)) {
            $existingPlayers[$id]['IsPinned'] = $true
        }
    }

    $pinnedContent = @()
    $mostNicknamesContent = @()
    $mostRecentUpdatesContent = @()
    $restContent = @()

    foreach ($id in $existingPlayers.Keys) {
        $nicknames = $existingPlayers[$id]['Nicknames'] -join "`n    - "
        $timeData = $existingPlayers[$id]['TimeData']
        if ($updatedPlayerIds -contains $id -and $timeData -eq 'no-time-data-old-version') {
            $timeData = $currentTime
        }
        if ($existingPlayers[$id]['IsPinned']) {
            $entry = "-----------------------------------`n*Pinned Player`n$id`n    - $nicknames`nlistplayered $timeData"
            $pinnedContent += $entry
        } elseif ($existingPlayers[$id]['Nicknames'].Count -gt 1) {
            $entry = "-----------------------------------`n$id`n    - $nicknames`nlistplayered $timeData"
            $mostNicknamesContent += $entry
        } elseif ($timeData -eq $currentTime) {
            $entry = "-----------------------------------`n$id`n    - $nicknames`nlistplayered $timeData"
            $mostRecentUpdatesContent += $entry
        } else {
            $entry = "-----------------------------------`n$id`n    - $nicknames`nlistplayered $timeData"
            $restContent += $entry
        }
    }

    $mostNicknamesContent = $mostNicknamesContent | Sort-Object { ($_ -split "`n").Count } -Descending

    $newContent = $pinnedContent + $mostNicknamesContent + $mostRecentUpdatesContent + $restContent
    $newContent -join "`n" | Set-Content -Path .\Chivalry2PlayersDatabase.log -Encoding UTF8
}

$window = New-Object System.Windows.Window
$window.Title = "Chivalry 2 listplayers Organizer 1.35 by vintertid from Discord"
$window.Width = 1200
$window.Height = 800

$mainGrid = New-Object System.Windows.Controls.Grid
$column1 = New-Object System.Windows.Controls.ColumnDefinition
$column2 = New-Object System.Windows.Controls.ColumnDefinition
$mainGrid.ColumnDefinitions.Add($column1)
$mainGrid.ColumnDefinitions.Add($column2)

$stackPanel = New-Object System.Windows.Controls.StackPanel
$stackPanel2 = New-Object System.Windows.Controls.StackPanel

$processButton = New-Object System.Windows.Controls.Button
$processButton.Content = "Process ListPlayers"
$processButton.HorizontalAlignment = "Center"
$processButton.VerticalAlignment = "Top"
$processButton.Margin = New-Object System.Windows.Thickness(10)
$processButton.Add_Click({
    Process-ListPlayers
    $textBox.Text = Get-Content -Path .\Chivalry2PlayersDatabase.log -Encoding UTF8 -Raw
})

$timeTextBlock = New-Object System.Windows.Controls.TextBlock
$timeTextBlock.HorizontalAlignment = "Center"
$timeTextBlock.Margin = New-Object System.Windows.Thickness(10)

$timer = New-Object System.Windows.Threading.DispatcherTimer
$timer.Interval = [TimeSpan]::FromSeconds(1)
$timer.Add_Tick({
    $timeTextBlock.Text = "Current Time: " + (Get-Date -Format "yyyy-MM-dd-HH:mm:ss UTCK")
})
$timer.Start()

$textBox = New-Object System.Windows.Controls.TextBox
$textBox.VerticalScrollBarVisibility = "Visible"
$textBox.HorizontalAlignment = "Stretch"
$textBox.Height = 500
$textBox.Margin = New-Object System.Windows.Thickness(10)
$textBox.IsReadOnly = $true

$searchBox = New-Object System.Windows.Controls.TextBox
$searchBox.HorizontalAlignment = "Stretch"
$searchBox.Margin = New-Object System.Windows.Thickness(10)
$searchBox.Height = 20

$searchButton = New-Object System.Windows.Controls.Button
$searchButton.Content = "Search"
$searchButton.HorizontalAlignment = "Center"
$searchButton.Margin = New-Object System.Windows.Thickness(10)
$searchButton.Add_Click({
    $searchText = $searchBox.Text
    if ([string]::IsNullOrWhiteSpace($searchText)) { return }

    $startIndex = $textBox.Text.IndexOf($searchText, $textBox.SelectionStart + $textBox.SelectionLength, [System.StringComparison]::OrdinalIgnoreCase)
    if ($startIndex -eq -1) {
        $startIndex = $textBox.Text.IndexOf($searchText, [System.StringComparison]::OrdinalIgnoreCase)
        if ($startIndex -eq -1) { return }
    }

    $textBox.Select($startIndex, $searchText.Length)
    $textBox.Focus()
    $textBox.ScrollToLine($textBox.GetLineIndexFromCharacterIndex($startIndex))
})

$textBox2 = New-Object System.Windows.Controls.TextBox
$textBox2.VerticalScrollBarVisibility = "Visible"
$textBox2.HorizontalAlignment = "Stretch"
$textBox2.Height = 500
$textBox2.Margin = New-Object System.Windows.Thickness(10)
$textBox2.AcceptsReturn = $true

$loadButton = New-Object System.Windows.Controls.Button
$loadButton.Content = "Load Pinned Players"
$loadButton.HorizontalAlignment = "Center"
$loadButton.VerticalAlignment = "Top"
$loadButton.Margin = New-Object System.Windows.Thickness(10)
$loadButton.Add_Click({
    if (Test-Path .\Chivalry2PinnedPlayers.log) {
        $textBox2.Text = Get-Content -Path .\Chivalry2PinnedPlayers.log -Raw
    }
})

$saveButton = New-Object System.Windows.Controls.Button
$saveButton.Content = "Save Pinned Players"
$saveButton.HorizontalAlignment = "Center"
$saveButton.VerticalAlignment = "Top"
$saveButton.Margin = New-Object System.Windows.Thickness(10)
$saveButton.Add_Click({
    $textBox2.Text | Set-Content -Path .\Chivalry2PinnedPlayers.log -Encoding UTF8
})

$stackPanel.Children.Add($processButton)
$stackPanel.Children.Add($timeTextBlock)
$stackPanel.Children.Add($textBox)

if (Test-Path .\Chivalry2PlayersDatabase.log) {
    $textBox.Text = Get-Content -Path .\Chivalry2PlayersDatabase.log -Encoding UTF8 -Raw
}

$stackPanel.Children.Add($searchBox)
$stackPanel.Children.Add($searchButton)

$stackPanel.SetValue([System.Windows.Controls.Grid]::ColumnProperty, 0)
$stackPanel2.Children.Add($textBox2)

if (Test-Path .\Chivalry2PinnedPlayers.log) {
    $textBox2.Text = Get-Content -Path .\Chivalry2PinnedPlayers.log -Raw
} else {
    New-Item -Path .\Chivalry2PinnedPlayers.log -ItemType File
}

$stackPanel2.Children.Add($loadButton)
$stackPanel2.Children.Add($saveButton)
$stackPanel2.SetValue([System.Windows.Controls.Grid]::ColumnProperty, 1)

$mainGrid.Children.Add($stackPanel)
$mainGrid.Children.Add($stackPanel2)

$window.Content = $mainGrid

$window.ShowDialog()

↓ Old Version


Changes in version 1.35

  • Better handle of player nicknames.

Changes in version 1.34

  • Clicking Process ListPlayers button also saves original listplayers contents from the clipboard.
  • Better handle of PlayFabPlayerId.

Changes in version 1.32

  • Fixed players with double quotation marks in their nickname are not processed.

Changes in version 1.31

  • Searching is not case sensitive.
  • Displays current time below “Process ListPlayers” button.

Changes in version 1.3

  • It is GUI with buttons.

↓ Legacy Version


This PowerShell script is crafted to effectively organize player data from the game Chivalry 2, enabling users to track name changes and monitor specific players of interest.

  • Updating the Player Database: Just It updates or generates a new file named Chivalry2PlayersDatabase.log, organizing players by their PlayFabPlayerIds and associated nicknames in a structured format.
  • Tracking Nickname Changes: For each PlayFabPlayerId, the script maintains a history of nicknames, facilitating the tracking of player name changes over time.
  • Prioritizing Pinned Players: The script ensures that players listed in the Chivalry2PinnedPlayers.log are placed at the top of the Chivalry2PlayersDatabase.log file, marked with a special indicator to highlight their “Pinned” status. This feature is especially useful for users aiming to closely monitor certain players, whether for administrative reasons or to keep tabs on friends or notable individuals in the game.

It interacts with two primary log files:

Chivalry2ListPlayers.log: Contains the current list of players, player nicknames and their unique PlayFabPlayerIds.

ServerName - example-server--beginner-10p--chivalry-2-live--12345678-1234-1234-1234-1234567890ab 192.0.2.1:52760
Name - PlayFabPlayerId - EOSPlayerId - Score - Kills - Deaths - Ping
<Nickname1> - <PlayFabPlayerId1> - -2030777152 - 250 - 5 - 1 ms
<Nickname2> - <PlayFabPlayerId2> - -2030777152 - 300 - 6 - 2 ms
...

Chivalry2PinnedPlayers.log (optional): Lists the PlayFabPlayerIds of players the user wishes to track more closely, referred to as “pinned” players within the script’s context.

<PlayFabPlayerId1>
<PlayFabPlayerId2>
<PlayFabPlayerId3>
...

The script’s functionalities include:

  • Updating the Player Database: It updates or generates a new file named Chivalry2PlayersDatabase.log, organizing players by their PlayFabPlayerIds and associated nicknames in a structured format.
  • Tracking Nickname Changes: For each PlayFabPlayerId, the script maintains a history of nicknames, facilitating the tracking of player name changes over time.
  • Prioritizing Pinned Players: The script ensures that players listed in the Chivalry2PinnedPlayers.log are placed at the top of the Chivalry2PlayersDatabase.log file, marked with a special indicator to highlight their “Pinned” status. This feature is especially useful for users aiming to closely monitor certain players, whether for administrative reasons or to keep tabs on friends or notable individuals in the game.

Changes in version 1.2

  • PlayFabPlayerIds with the most recent update follow PlayFabPlayerIds with the most nicknames.
  • When updating the database with the listplayers output, the PlayFabPlayerId included in the listplayers output will have the current time recorded.

Changes in version 1.1

  • After Pinned Players, PlayFabPlayerIds with the most nicknames will be placed next.