├── .gitignore ├── .vscode ├── settings.json └── tasks.json ├── PSTelegramAPI.bootstrap.ps1 ├── PSTelegramAPI.build.ps1 ├── PSTelegramAPI ├── PSTelegramAPI.psd1 ├── PSTelegramAPI.psm1 ├── lib │ └── TLSharp.0.1.0.379 │ │ ├── BigMath.dll │ │ ├── Ionic.ZLib.dll │ │ ├── TLSharp.Core.dll │ │ └── TeleSharp.TL.dll ├── private │ ├── ConvertFrom-TLUserDialog.ps1 │ ├── ConvertTo-TLInputPeer.ps1 │ └── Wait-TLAsync.ps1 └── public │ ├── Get-TLContacts.ps1 │ ├── Get-TLHistory.ps1 │ ├── Get-TLUserDialogs.ps1 │ ├── Invoke-TLSendMessage.ps1 │ └── New-TLClient.ps1 ├── README.md ├── Tests └── PSTelegramAPI.Tests.ps1 └── azure-pipelines.yml /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | *.dat 3 | output/ 4 | testresults/ -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | // When enabled, will trim trailing whitespace when you save a file. 3 | "files.trimTrailingWhitespace": true 4 | } 5 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | // Available variables which can be used inside of strings. 2 | // ${workspaceRoot}: the root folder of the team 3 | // ${file}: the current opened file 4 | // ${relativeFile}: the current opened file relative to workspaceRoot 5 | // ${fileBasename}: the current opened file's basename 6 | // ${fileDirname}: the current opened file's dirname 7 | // ${fileExtname}: the current opened file's extension 8 | // ${cwd}: the current working directory of the spawned process 9 | { 10 | // See https://go.microsoft.com/fwlink/?LinkId=733558 11 | // for the documentation about the tasks.json format 12 | "version": "2.0.0", 13 | 14 | // Start PowerShell 15 | "windows": { 16 | "command": "${env:windir}/System32/WindowsPowerShell/v1.0/powershell.exe", 17 | //"command": "${env:ProgramFiles}/PowerShell/6.0.0/powershell.exe", 18 | "args": [ "-NoProfile", "-ExecutionPolicy", "Bypass" ] 19 | }, 20 | "linux": { 21 | "command": "/usr/bin/powershell", 22 | "args": [ "-NoProfile" ] 23 | }, 24 | "osx": { 25 | "command": "/usr/local/bin/powershell", 26 | "args": [ "-NoProfile" ] 27 | }, 28 | 29 | // Associate with test task runner 30 | "tasks": [ 31 | { 32 | "taskName": "Test", 33 | "suppressTaskName": true, 34 | "isTestCommand": true, 35 | "args": [ 36 | "Write-Host 'Invoke-Build -Task Test'; $ProgressPreference = 'SilentlyContinue'; Invoke-Build -Task Test;", 37 | "Invoke-Command { Write-Host 'Completed Test task in task runner.' }" 38 | ], 39 | "problemMatcher": "$pester" 40 | } 41 | ] 42 | } 43 | -------------------------------------------------------------------------------- /PSTelegramAPI.bootstrap.ps1: -------------------------------------------------------------------------------- 1 | using namespace Microsoft.PowerShell.Commands 2 | [CmdletBinding()] 3 | param( 4 | # 5 | [ValidateSet("CurrentUser", "AllUsers")] 6 | $Scope = "CurrentUser" 7 | ) 8 | 9 | [ModuleSpecification[]]$RequiredModules = @( 10 | @{ ModuleName = "InvokeBuild"; RequiredVersion = "5.4.2" } 11 | @{ ModuleName = "Pester"; RequiredVersion = "4.4.4" } 12 | @{ ModuleName = "BuildHelpers"; RequiredVersion = "2.0.3" } 13 | ) 14 | 15 | $Policy = (Get-PSRepository PSGallery).InstallationPolicy 16 | Set-PSRepository PSGallery -InstallationPolicy Trusted 17 | 18 | try { 19 | $RequiredModules | Install-Module -Scope $Scope -Repository PSGallery -SkipPublisherCheck -Verbose 20 | } finally { 21 | Set-PSRepository PSGallery -InstallationPolicy $Policy 22 | } 23 | 24 | $RequiredModules | Import-Module -------------------------------------------------------------------------------- /PSTelegramAPI.build.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .Synopsis 3 | Build script (https://github.com/nightroman/Invoke-Build) 4 | #> 5 | 6 | param ($Configuration = 'Development') 7 | 8 | #region Set-BuildEnvironment 9 | Try { Set-BuildEnvironment -ErrorAction SilentlyContinue -Force } Catch { } 10 | #endregion 11 | 12 | #region use the most strict mode 13 | Set-StrictMode -Version Latest 14 | #endregion 15 | 16 | #region Task to Update TLSharp Package if newer version is released 17 | task UpdateTLSharpPackage { 18 | 19 | # Check current TLSharp Package version 20 | # Get TLSharp.Core.dll file properties 21 | $ProductionPath = Get-ChildItem -Path .\lib\ -Filter TLSharp.Core.dll -Recurse | Select-Object -Expand Directory 22 | $ProductionFolder = Split-Path $ProductionPath -Leaf 23 | [Version]$ProductVersion = ($ProductionFolder -Split "\.")[-4,-3,-2,-1] -Join "." 24 | Write-Output -InputObject ('ProductVersion {0}' -f $ProductVersion) 25 | 26 | # Check latest version TLSharpPackage 27 | $LatestPackage = Find-Package -Name TLSharp -Provider Nuget -Source 'https://www.nuget.org/api/v2' 28 | [Version]$LatestVersion = $LatestPackage.Version 29 | Write-Output -InputObject ('Latest Version {0}' -f $LatestVersion) 30 | 31 | #Download latest version when newer 32 | If ($LatestVersion -gt $ProductVersion) { 33 | 34 | Write-Output -InputObject ('Newer version {0} available' -f $LatestVersion) 35 | #Install TLSharp package to temp folder 36 | $LatestPackage | Install-Package -Force -Confirm:$false | Out-Null 37 | $LatestPackage = Get-Package -Name TLSharp 38 | $LatestPath = Split-Path $LatestPackage.Source 39 | $LatestFolder = Split-Path $LatestPath -Leaf 40 | 41 | Write-Output -InputObject ('Remove current TLSharp binaries') 42 | Remove-Item -Path $ProductionFolder -Recurse -Force -Confirm:$false 43 | 44 | Write-Output -InputObject ('Copy TLSharp binaries to PSTelegramAPI Module') 45 | New-Item -Path ".\lib\${LatestFolder}" -ItemType Directory | Out-Null 46 | Get-ChildItem -Path $LatestPath -Filter *.dll -Recurse | Copy-Item -Destination ".\lib\${LatestFolder}" 47 | 48 | } 49 | else { 50 | Write-Output -InputObject ('Current local version {0}. Latest version {1}' -f $ProductVersion, $LatestVersion) 51 | } 52 | } 53 | #endregion 54 | 55 | #region Task to run all Pester tests in folder .\tests 56 | task Test { 57 | 58 | $OutputPath = New-Item -Path '.\TestResults' -ItemType Directory -Force -Verbose 59 | 60 | $PesterParams = @{ 61 | Script = '.\Tests' 62 | OutputFile = "${OutputPath}\TestResults-PSTelegramAPI.xml" 63 | CodeCoverage = 'PSTelegramAPI\*\*.ps1' 64 | CodeCoverageOutputFile = "${OutputPath}\CodeCoverage-PSTelegramAPI.xml" 65 | CodeCoverageOutputFileFormat = 'JaCoCo' 66 | } 67 | 68 | $Result = Invoke-Pester @PesterParams -PassThru 69 | 70 | if ($Result.FailedCount -gt 0) { 71 | throw 'Pester tests failed' 72 | } 73 | 74 | } 75 | #endregion 76 | 77 | #region Task to update the Module Manifest file with info from the Changelog in Readme. 78 | task UpdateManifest { 79 | # Import PlatyPS. Needed for parsing README for Change Log versions 80 | #Import-Module -Name PlatyPS 81 | 82 | $ManifestPath = '.\PSTelegramAPI\PSTelegramAPI.psd1' 83 | $ModuleManifest = Test-ModuleManifest -Path $ManifestPath 84 | [System.Version]$ManifestVersion = $ModuleManifest.Version 85 | Write-Output -InputObject ('Manifest Version : {0}' -f $ManifestVersion) 86 | 87 | $PSGalleryModule = Find-Module -Name PSTelegramAPI -Repository PSGallery 88 | [System.Version]$PSGalleryVersion = $PSGalleryModule.Version 89 | Write-Output -InputObject ('PSGallery Version : {0}' -f $PSGalleryVersion) 90 | 91 | If ($PSGalleryVersion -ge $ManifestVersion) { 92 | 93 | [System.Version]$Version = New-Object -TypeName System.Version -ArgumentList ($PSGalleryVersion.Major, $PSGalleryVersion.Minor, ($PSGalleryVersion.Build + 1)) 94 | Write-Output -InputObject ('Updated Version : {0}' -f $Version) 95 | Update-ModuleManifest -ModuleVersion $Version -Path .\PSTelegramAPI\PSTelegramAPI.psd1 # -ReleaseNotes $ReleaseNotes 96 | 97 | } 98 | 99 | } 100 | #endregion 101 | 102 | #region Task to Publish Module to PowerShell Gallery 103 | task PublishModule -If ($Configuration -eq 'Production') { 104 | Try { 105 | 106 | # Publish to gallery with a few restrictions 107 | if( 108 | $env:BHModulePath -and 109 | $env:BHBuildSystem -ne 'Unknown' -and 110 | $env:BHBranchName -eq "master" -and 111 | $env:BHCommitMessage -match '!publish' 112 | ) 113 | { 114 | 115 | # Build a splat containing the required details and make sure to Stop for errors which will trigger the catch 116 | $params = @{ 117 | Path = ".\PSTelegramAPI" 118 | NuGetApiKey = $ENV:NuGetApiKey 119 | ErrorAction = 'Stop' 120 | } 121 | Publish-Module @params 122 | Write-Output -InputObject ('PSTelegramAPI PowerShell Module version published to the PowerShell Gallery') 123 | 124 | } 125 | else 126 | { 127 | "Skipping deployment: To deploy, ensure that...`n" + 128 | "`t* You are in a known build system (Current: $ENV:BHBuildSystem)`n" + 129 | "`t* You are committing to the master branch (Current: $ENV:BHBranchName) `n" + 130 | "`t* Your commit message includes !deploy (Current: $ENV:BHCommitMessage)" | 131 | Write-Host 132 | } 133 | 134 | } 135 | Catch { 136 | throw $_ 137 | } 138 | } 139 | #endregion 140 | 141 | #region Default Task. Runs Test, UpdateManifest, PublishModule Tasks 142 | task . Test, UpdateManifest, PublishModule 143 | #endregion -------------------------------------------------------------------------------- /PSTelegramAPI/PSTelegramAPI.psd1: -------------------------------------------------------------------------------- 1 | # 2 | # Module manifest for module 'PSTelegramAPI' 3 | # 4 | # Generated by: Marc R Kellerman 5 | # 6 | # Generated on: 1/6/2019 7 | # 8 | 9 | @{ 10 | 11 | # Script module or binary module file associated with this manifest. 12 | RootModule = 'PSTelegramAPI.psm1' 13 | 14 | # Version number of this module. 15 | ModuleVersion = '0.0.10' 16 | 17 | # Supported PSEditions 18 | # CompatiblePSEditions = @() 19 | 20 | # ID used to uniquely identify this module 21 | GUID = 'f98f3474-fc4c-48b7-9cc4-b7284ed5798e' 22 | 23 | # Author of this module 24 | Author = 'Marc R Kellerman' 25 | 26 | # Company or vendor of this module 27 | CompanyName = '@mkellerman' 28 | 29 | # Copyright statement for this module 30 | Copyright = '(c) 2019 Marc R Kellerman. All rights reserved.' 31 | 32 | # Description of the functionality provided by this module 33 | Description = 'PowerShell Module for Telegram API' 34 | 35 | # Minimum version of the Windows PowerShell engine required by this module 36 | # PowerShellVersion = '' 37 | 38 | # Name of the Windows PowerShell host required by this module 39 | # PowerShellHostName = '' 40 | 41 | # Minimum version of the Windows PowerShell host required by this module 42 | # PowerShellHostVersion = '' 43 | 44 | # Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only. 45 | # DotNetFrameworkVersion = '' 46 | 47 | # Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only. 48 | # CLRVersion = '' 49 | 50 | # Processor architecture (None, X86, Amd64) required by this module 51 | # ProcessorArchitecture = '' 52 | 53 | # Modules that must be imported into the global environment prior to importing this module 54 | # RequiredModules = @() 55 | 56 | # Assemblies that must be loaded prior to importing this module 57 | # RequiredAssemblies = @() 58 | 59 | # Script files (.ps1) that are run in the caller's environment prior to importing this module. 60 | # ScriptsToProcess = @() 61 | 62 | # Type files (.ps1xml) to be loaded when importing this module 63 | # TypesToProcess = @() 64 | 65 | # Format files (.ps1xml) to be loaded when importing this module 66 | # FormatsToProcess = @() 67 | 68 | # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess 69 | # NestedModules = @() 70 | 71 | # Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. 72 | FunctionsToExport = '*' 73 | 74 | # Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export. 75 | CmdletsToExport = '*' 76 | 77 | # Variables to export from this module 78 | VariablesToExport = '*' 79 | 80 | # Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export. 81 | AliasesToExport = '*' 82 | 83 | # DSC resources to export from this module 84 | # DscResourcesToExport = @() 85 | 86 | # List of all modules packaged with this module 87 | # ModuleList = @() 88 | 89 | # List of all files packaged with this module 90 | # FileList = @() 91 | 92 | # Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell. 93 | PrivateData = @{ 94 | 95 | PSData = @{ 96 | 97 | # Tags applied to this module. These help with module discovery in online galleries. 98 | # Tags = @() 99 | 100 | # A URL to the license for this module. 101 | # LicenseUri = '' 102 | 103 | # A URL to the main website for this project. 104 | ProjectUri = 'https://github.com/mkellerman/PSTelegramAPI' 105 | 106 | # A URL to an icon representing this module. 107 | # IconUri = '' 108 | 109 | # ReleaseNotes of this module 110 | # ReleaseNotes = '' 111 | 112 | # Prerelease string of this module 113 | # Prerelease = '' 114 | 115 | # Flag to indicate whether the module requires explicit user acceptance for install/update 116 | # RequireLicenseAcceptance = $false 117 | 118 | # External dependent modules of this module 119 | # ExternalModuleDependencies = @() 120 | 121 | } # End of PSData hashtable 122 | 123 | } # End of PrivateData hashtable 124 | 125 | # HelpInfo URI of this module 126 | # HelpInfoURI = '' 127 | 128 | # Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. 129 | # DefaultCommandPrefix = '' 130 | 131 | } 132 | 133 | -------------------------------------------------------------------------------- /PSTelegramAPI/PSTelegramAPI.psm1: -------------------------------------------------------------------------------- 1 | 2 | # Import TLSharp binaries. 3 | $TLSharpDll = Get-ChildItem -Path $PSScriptRoot\lib\ -Filter TLSharp.Core.dll -Recurse 4 | Import-Module -Name $TLSharpDll.FullName | Out-Null 5 | 6 | #Get public and private function definition files. 7 | $Public = @( Get-ChildItem -Path $PSScriptRoot\public\*.ps1 -ErrorAction SilentlyContinue ) 8 | $Private = @( Get-ChildItem -Path $PSScriptRoot\private\*.ps1 -ErrorAction SilentlyContinue ) 9 | 10 | #Dot source the files. 11 | Foreach ($import in @($Public + $Private)) { 12 | Try { 13 | . $import.fullname 14 | } 15 | Catch { 16 | Write-Error -Message "Failed to import function $($import.fullname): $_" 17 | } 18 | } 19 | 20 | Export-ModuleMember -Function $Public.Basename -------------------------------------------------------------------------------- /PSTelegramAPI/lib/TLSharp.0.1.0.379/BigMath.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mkellerman/PSTelegramAPI/b4b19cf35c53ba3a91f44ad95c54485b71240a0d/PSTelegramAPI/lib/TLSharp.0.1.0.379/BigMath.dll -------------------------------------------------------------------------------- /PSTelegramAPI/lib/TLSharp.0.1.0.379/Ionic.ZLib.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mkellerman/PSTelegramAPI/b4b19cf35c53ba3a91f44ad95c54485b71240a0d/PSTelegramAPI/lib/TLSharp.0.1.0.379/Ionic.ZLib.dll -------------------------------------------------------------------------------- /PSTelegramAPI/lib/TLSharp.0.1.0.379/TLSharp.Core.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mkellerman/PSTelegramAPI/b4b19cf35c53ba3a91f44ad95c54485b71240a0d/PSTelegramAPI/lib/TLSharp.0.1.0.379/TLSharp.Core.dll -------------------------------------------------------------------------------- /PSTelegramAPI/lib/TLSharp.0.1.0.379/TeleSharp.TL.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mkellerman/PSTelegramAPI/b4b19cf35c53ba3a91f44ad95c54485b71240a0d/PSTelegramAPI/lib/TLSharp.0.1.0.379/TeleSharp.TL.dll -------------------------------------------------------------------------------- /PSTelegramAPI/private/ConvertFrom-TLUserDialog.ps1: -------------------------------------------------------------------------------- 1 | 2 | function ConvertFrom-TLUserDialog { 3 | 4 | [cmdletbinding()] 5 | Param( 6 | [object]$TLUserDialog 7 | ) 8 | 9 | Begin { 10 | 11 | #Write-Verbose "[$(Get-Date)] [BEGIN] $($MyInvocation.MyCommand)" 12 | 13 | $Results = New-Object System.Collections.ArrayList 14 | 15 | } 16 | 17 | Process { 18 | 19 | ForEach ($TLDialog in ($TLUserDialog.Dialogs | Select-Object *)) { 20 | 21 | Switch ($TLDialog.Peer.GetType().Name) { 22 | 'TLPeerUser' { 23 | $TLPeer = $TLUserDialog.Users.Where({$_.Id -eq $TLDialog.Peer.UserId}) | Select-Object -Last 1 24 | $TLMessage = $TLUserDialog.Messages.Where({($_.FromId -eq $TLPeer.Id) -or ($_.ToId.UserId -eq $TLPeer.Id)}) | Select-Object -Last 1 25 | } 26 | 'TLPeerChat' { 27 | $TLPeer = $TLUserDialog.Chats.Where({$_.Id -eq $TLDialog.Peer.ChatId}) | Select-Object -Last 1 28 | $TLMessage = $TLUserDialog.Messages.Where({$_.ToId.ChatId -eq $TLPeer.Id}) | Select-Object -Last 1 29 | } 30 | 'TLPeerChannel' { 31 | $TLPeer = $TLUserDialog.Chats.Where({$_.Id -eq $TLDialog.Peer.ChannelId}) | Select-Object -Last 1 32 | $TLMessage = $TLUserDialog.Messages.Where({$_.ToId.ChannelId -eq $TLPeer.Id}) | Select-Object -Last 1 33 | } 34 | } 35 | 36 | $TLDialog | Add-Member -MemberType NoteProperty -Name Peer -Value $TLPeer -Force 37 | $TLDialog | Add-Member -MemberType NoteProperty -Name Message -Value $TLMessage 38 | 39 | [void] $Results.Add($TLDialog) 40 | 41 | } 42 | 43 | } 44 | 45 | End { 46 | 47 | #Write-Verbose "[$(Get-Date)] [END ] $($MyInvocation.MyCommand)" 48 | 49 | Return $Results 50 | 51 | } 52 | 53 | } -------------------------------------------------------------------------------- /PSTelegramAPI/private/ConvertTo-TLInputPeer.ps1: -------------------------------------------------------------------------------- 1 | 2 | function ConvertTo-TLInputPeer { 3 | 4 | [cmdletbinding()] 5 | Param( 6 | [parameter(ValueFromPipeline)] 7 | [object]$TLPeer 8 | ) 9 | 10 | Begin { 11 | 12 | Write-Verbose "[$(Get-Date)] [BEGIN] $($MyInvocation.MyCommand)" 13 | 14 | } 15 | 16 | Process { 17 | 18 | Switch -Wildcard ($TLPeer.GetType().Name) { 19 | 'TLUser*' { New-Object TeleSharp.TL.TLInputPeerUser -Property @{ UserId = $TLPeer.Id; AccessHash = $TLPeer.AccessHash } } 20 | 'TLChat*' { New-Object TeleSharp.TL.TLInputPeerChat -Property @{ ChatId = $TLPeer.Id } } 21 | 'TLChannel*' { New-Object TeleSharp.TL.TLInputPeerChannel -Property @{ ChannelId = $TLPeer.Id; AccessHash = $TLPeer.AccessHash } } 22 | Default { Throw 'Invalid TLPeer object.'} 23 | } 24 | 25 | } 26 | 27 | End { 28 | 29 | Write-Verbose "[$(Get-Date)] [END ] $($MyInvocation.MyCommand)" 30 | 31 | } 32 | 33 | } -------------------------------------------------------------------------------- /PSTelegramAPI/private/Wait-TLAsync.ps1: -------------------------------------------------------------------------------- 1 | 2 | function Wait-TLAsync { 3 | 4 | [cmdletbinding()] 5 | Param ( 6 | [parameter(ValueFromPipeline)] 7 | [System.Threading.Tasks.Task]$AsyncTask, 8 | [switch]$PassThru 9 | ) 10 | 11 | Process { 12 | 13 | While ($AsyncTask.Status -eq 'WaitingForActivation') { 14 | Start-Sleep -Milliseconds 100 15 | } 16 | 17 | If ($AsyncTask.IsFaulted -or $AsyncTask.IsCanceled) { 18 | 19 | If ([int]$TimeToWait = $AsyncTask.Exception.InnerException.TimeToWait.TotalSeconds) { 20 | Write-Warning "Wait-TLAsync: Flood Prevention (TimeToWait: ${TimeToWait})." 21 | Start-Sleep -Seconds $TimeToWait 22 | Return $False 23 | } 24 | 25 | Throw $AsyncTask.Exception.InnerException.Message 26 | 27 | } 28 | 29 | If ($AsyncTask.IsCompleted) { 30 | While (-Not $AsyncTask.Result) { Start-Sleep -Milliseconds 100 } 31 | } 32 | 33 | If ($PassThru) { 34 | Return $AsyncTask 35 | } Else { 36 | Return $AsyncTask.Result 37 | } 38 | 39 | } 40 | 41 | } -------------------------------------------------------------------------------- /PSTelegramAPI/public/Get-TLContacts.ps1: -------------------------------------------------------------------------------- 1 | function Get-TLContacts { 2 | 3 | 4 | [cmdletbinding()] 5 | Param( 6 | [Parameter(Mandatory = $true)] 7 | [TLSharp.Core.TelegramClient]$TLClient 8 | ) 9 | 10 | Begin { 11 | 12 | Write-Verbose "[$(Get-Date)] [BEGIN] $($MyInvocation.MyCommand)" 13 | 14 | } 15 | 16 | Process { 17 | 18 | Do { 19 | Write-Verbose "[$(Get-Date)] [INFO ] > TLClient.GetContactsAsync()" 20 | $Result = $TLClient.GetContactsAsync() | Wait-TLAsync 21 | } While ($Result -eq $False) 22 | 23 | } 24 | 25 | End { 26 | 27 | Write-Verbose "[$(Get-Date)] [END ] $($MyInvocation.MyCommand)" 28 | 29 | Return $Result 30 | 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /PSTelegramAPI/public/Get-TLHistory.ps1: -------------------------------------------------------------------------------- 1 | function Get-TLHistory { 2 | 3 | [cmdletbinding()] 4 | Param( 5 | $TLClient, 6 | [object]$TLPeer, 7 | [int]$OffsetId = 0, 8 | [int]$OffsetDate = 0, 9 | [int]$AddOffset = 0, 10 | [int]$Limit = [int]::MaxValue, 11 | [int]$MaxId = 0, 12 | [int]$MinId = 0, 13 | [switch]$PassThru 14 | ) 15 | 16 | Begin { 17 | 18 | Write-Verbose "[$(Get-Date)] [BEGIN] $($MyInvocation.MyCommand)" 19 | 20 | $MessageTotal = 0 21 | $LimitPerRequest = 100 22 | 23 | $Results = New-Object System.Collections.ArrayList 24 | 25 | $TLInputPeer = ConvertTo-TLInputPeer -TLPeer $TLPeer -Verbose:$false 26 | 27 | } 28 | 29 | Process { 30 | 31 | 32 | 33 | Do { 34 | 35 | If ($Limit -lt $LimitPerRequest) { $LimitPerRequest = $Limit } 36 | 37 | Do { 38 | Write-Verbose "[$(Get-Date)] [INFO ] > GetHistoryAsync ($TLInputPeer, ${OffsetId}, ${OffsetDate}, ${AddOffSet}, ${LimitPerRequest}, ${MaxId}, ${MinId})" 39 | $Result = $TLClient.GetHistoryAsync($TLInputPeer, $OffsetId, $OffsetDate, $AddOffSet, $LimitPerRequest, $MaxId, $MinId) | Wait-TLAsync 40 | } While ($Result -eq $false) 41 | 42 | [void] $Results.Add($Result) 43 | 44 | $OffsetId = $Result.Messages[-1].Id 45 | $Limit -= $LimitPerRequest 46 | 47 | 48 | } Until (($Limit -eq 0) -or ($Result.Messages.Count -lt $LimitPerRequest)) 49 | 50 | } 51 | 52 | End { 53 | 54 | Switch ($Results[0].GetType().Name) { 55 | 'TLChannelMessages' { $MessageCount = $Results[0].Count } 56 | 'TLMessagesSlice' { $MessageCount = $Results[0].Count } 57 | 'TLMessages' { $MessageCount = $Results[0].Messages.Count } 58 | Default { 59 | Write-Warning "Unknown Type returned : $_" 60 | } 61 | } 62 | 63 | Write-Verbose "[$(Get-Date)] [INFO ] > Messages: $($Results.Messages.Count) | Users: $($Results.Users.Count) | Chats: $($Results.Chats.Count) | Count: $($MessageCount)" 64 | 65 | If ($PassThru) { 66 | 67 | ForEach ($Result in $Results) { $Result } 68 | 69 | } Else { 70 | 71 | [PSCustomObject]@{ 72 | InputPeer = $TLInputPeer 73 | Users = $Results.Users 74 | Chats = $Results.Chats 75 | Messages = $Results.Messages 76 | Count = $MessageCount 77 | } 78 | 79 | } 80 | 81 | Write-Verbose "[$(Get-Date)] [END ] $($MyInvocation.MyCommand)" 82 | 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /PSTelegramAPI/public/Get-TLUserDialogs.ps1: -------------------------------------------------------------------------------- 1 | function Get-TLUserDialogs { 2 | 3 | [cmdletbinding()] 4 | Param( 5 | [Parameter(Mandatory = $true)] 6 | [TLSharp.Core.TelegramClient]$TLClient, 7 | [Parameter(Mandatory = $false)] 8 | [int]$OffsetDate = 0, 9 | [Parameter(Mandatory = $false)] 10 | [int]$OffsetId = 0, 11 | [Parameter(Mandatory = $false)] 12 | [TeleSharp.TL.TLAbsPeer]$OffsetPeer = $Null, 13 | [Parameter(Mandatory = $false)] 14 | [int]$Limit = [int]::MaxValue, 15 | [Parameter(Mandatory = $false)] 16 | [switch]$PassThru 17 | 18 | ) 19 | 20 | Begin { 21 | 22 | Write-Verbose "[$(Get-Date)] [BEGIN] $($MyInvocation.MyCommand)" 23 | 24 | $LimitPerRequest = 100 25 | $Results = New-Object System.Collections.ArrayList 26 | 27 | } 28 | 29 | Process { 30 | 31 | Do { 32 | 33 | If ($Limit -lt $LimitPerRequest) { $LimitPerRequest = $Limit } 34 | 35 | Write-Verbose "[$(Get-Date)] [INFO ] > GetUserDialogsAsync (${OffsetDate}, ${OffsetId}, ${OffsetPeer}, ${LimitPerRequest})" 36 | $Result = $TLClient.GetUserDialogsAsync($OffsetDate, $OffsetId, $OffsetPeer, $LimitPerRequest) | Wait-TLAsync 37 | [void] $Results.Add($Result) 38 | 39 | $OffsetDate = $Result.Messages.Date | Sort-Object | Select-Object -First 1 40 | $Limit -= $Result.Dialogs.Count 41 | 42 | } Until (($Result.Dialogs.Count -lt $LimitPerRequest) -or ($Results.Dialogs.Count -ge $Limit)) 43 | 44 | } 45 | 46 | End { 47 | 48 | Write-Verbose "[$(Get-Date)] [INFO ] > Dialogs: $($Results.Dialogs.Count) | Users: $($Results.Users.Count) | Chats: $($Results.Chats.Count) | Messages: $($Results.Messages.Count)" 49 | 50 | If ($PassThru) { 51 | 52 | ForEach ($Result in $Results) { $Result } 53 | 54 | } Else { 55 | 56 | $Result = [PSCustomObject]@{ 57 | Dialogs = $Results.Dialogs 58 | Users = $Results.Users 59 | Chats = $Results.Chats 60 | Messages = $Results.Messages 61 | } 62 | 63 | ConvertFrom-TLUserDialog -TLUserDialog $Result -Verbose:$false 64 | 65 | } 66 | 67 | Write-Verbose "[$(Get-Date)] [END ] $($MyInvocation.MyCommand)" 68 | 69 | } 70 | 71 | } -------------------------------------------------------------------------------- /PSTelegramAPI/public/Invoke-TLSendMessage.ps1: -------------------------------------------------------------------------------- 1 | function Invoke-TLSendMessage { 2 | 3 | 4 | [cmdletbinding()] 5 | Param( 6 | [Parameter(Mandatory = $true)] 7 | [TLSharp.Core.TelegramClient]$TLClient, 8 | 9 | [Parameter(Mandatory = $true)] 10 | [object]$TLPeer, 11 | 12 | [Parameter(Mandatory = $true)] 13 | [object]$Message 14 | ) 15 | 16 | Begin { 17 | 18 | Write-Verbose "[$(Get-Date)] [BEGIN] $($MyInvocation.MyCommand)" 19 | 20 | $TLInputPeer = ConvertTo-TLInputPeer -TLPeer $TLPeer -Verbose:$false 21 | 22 | } 23 | 24 | Process { 25 | 26 | Do { 27 | Write-Verbose "[$(Get-Date)] [INFO ] > TLClient.GetContactsAsync()" 28 | $Result = $TLClient.SendMessageAsync($TLInputPeer, $Message) | Wait-TLAsync 29 | } While ($Result -eq $False) 30 | 31 | } 32 | 33 | End { 34 | 35 | Write-Verbose "[$(Get-Date)] [END ] $($MyInvocation.MyCommand)" 36 | 37 | Return $Result 38 | 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /PSTelegramAPI/public/New-TLClient.ps1: -------------------------------------------------------------------------------- 1 | function New-TLClient { 2 | 3 | [cmdletbinding()] 4 | Param( 5 | [Parameter(Mandatory = $true)] 6 | [int]$ApiId, 7 | 8 | [Parameter(Mandatory = $true)] 9 | [string]$ApiHash, 10 | 11 | [Parameter(Mandatory = $true)] 12 | [int64]$PhoneNumber 13 | ) 14 | 15 | Begin { 16 | 17 | Write-Verbose "[$(Get-Date)] [BEGIN] $($MyInvocation.MyCommand)" 18 | 19 | } 20 | 21 | Process { 22 | 23 | function New-TelegramClient ($apiId, $apiHash, $store = $Null, $sessionUserId, $handler = $Null) { 24 | Write-Verbose "[$(Get-Date)] [INFO ] > [TLSharp.Core.TelegramClient]::New(${ApiId}, '${ApiHash}', Null, ${sessionUserId}, Null)" 25 | [TLSharp.Core.TelegramClient]::New($apiId, $apiHash, $store, $sessionUserId, $handler) 26 | } 27 | 28 | $TLClient = New-TelegramClient -apiId $ApiId -apiHash $ApiHash -sessionUserId $PhoneNumber 29 | 30 | Do { 31 | Write-Verbose "[$(Get-Date)] [INFO ] > TLClient.ConnectAsync()" 32 | $Result = $TLClient.ConnectAsync() | Wait-TLAsync 33 | } While ($Result -eq $false) 34 | 35 | If (-Not $TLClient.IsUserAuthorized()) { 36 | 37 | Write-Verbose "[$(Get-Date)] [INFO ] > TLClient.SendCodeRequestAsync('+${PhoneNumber}')" 38 | $Hash = $TLClient.SendCodeRequestAsync("+${PhoneNumber}") | Wait-TLAsync 39 | 40 | $Code = Read-Host "Code from telegram" 41 | Write-Verbose "[$(Get-Date)] [INFO ] > TLClient.MakeAuthAsync(${PhoneNumber}, '${Hash}', ${Code})" 42 | $Result = $TLClient.MakeAuthAsync($PhoneNumber, $Hash, $Code) | Wait-TLAsync 43 | 44 | } 45 | 46 | } 47 | 48 | End { 49 | 50 | Write-Verbose "[$(Get-Date)] [END ] $($MyInvocation.MyCommand)" 51 | 52 | Return $TLClient 53 | 54 | } 55 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![PSGallery Version](https://img.shields.io/powershellgallery/v/PSTelegramAPI.svg?style=for-the-badge&label=PowerShell%20Gallery)](https://www.powershellgallery.com/packages/PSTelegramAPI/) 2 | [![PSGallery Downloads](https://img.shields.io/powershellgallery/dt/PSTelegramAPI.svg?style=for-the-badge&label=Downloads)](https://www.powershellgallery.com/packages/PSTelegramAPI/) 3 | 4 | [![Azure Pipeline](https://img.shields.io/azure-devops/build/mkellerman/PSTelegramAPI/3.svg?style=for-the-badge&label=Azure%20Pipeline)](https://dev.azure.com/mkellerman/PSTelegramAPI/_build?definitionId=3) 5 | [![Analytics](https://ga-beacon.appspot.com/UA-133882862-1/PSTelegramAPI?pixel)](https://github.com/mkellerman) 6 | 7 | # PSTelegramAPI 8 | 9 | PowerShell Module for Telegram APIs 10 | 11 | # Install PSTelegramAPI from PSGallery 12 | ```powershell 13 | Install-Module PSTelegramAPI -Scope CurrentUser 14 | ``` 15 | 16 | # Examples 17 | 18 | ```powershell 19 | Import-Module PSTelegramAPI 20 | 21 | # Establish connection to Telegram 22 | $TLClient = New-TLClient -apiId $ENV:TLApiId -apiHash $ENV:TLApiHash -phoneNumber $ENV:TLPhoneNumber 23 | 24 | # Get List of User Dialogs 25 | $TLUserDialogs = Get-TLUserDialogs -TLClient $TLClient 26 | 27 | # Get latest 100 messages from each User in List 28 | ForEach ($User in $TLUserDialog) { 29 | $TLHistory = Get-TLHistory -TLClient $TLClient -Peer $User.Peer -Limit 100 30 | } 31 | 32 | # Find a specific User 33 | $TLPeer = $TLUserDialogs.Where({ $_.Peer.Username -eq 'mkellerman' }).Peer 34 | 35 | # Send message to User 36 | Invoke-TLSendMessage -TLClient $TLClient -TLPeer $TLPeer -Message 'Hello World' 37 | ``` 38 | 39 | # Completed 40 | 41 | * Get-TLUserDialogs 42 | * Get-TLContacts 43 | * Get-TLHistory 44 | * Invoke-TLSendMessage 45 | 46 | # References 47 | 48 | * [PSTelegramAPI](https://www.powershellgallery.com/packages/PSTelegramAPI/) : PowerShell Gallery 49 | * [TLSharp](https://github.com/sochix/TLSharp) : Telegram client library implemented in C# 50 | -------------------------------------------------------------------------------- /Tests/PSTelegramAPI.Tests.ps1: -------------------------------------------------------------------------------- 1 | Try { Set-BuildEnvironment -Path "${PSScriptRoot}\.." -ErrorAction SilentlyContinue -Force } Catch { } 2 | 3 | If (-Not $ENV:TLApiId) { $ENV:TLApiId = [Environment]::GetEnvironmentVariable("TLApiId", "User") } 4 | If (-Not $ENV:TLApiHash) { $ENV:TLApiHash = [Environment]::GetEnvironmentVariable("TLApiHash", "User") } 5 | If (-Not $ENV:TLPhoneNumber) { $ENV:TLPhoneNumber = [Environment]::GetEnvironmentVariable("TLPhoneNumber", "User") } 6 | 7 | Remove-Module $ENV:BHProjectName -ErrorAction SilentlyContinue -Force -Confirm:$False 8 | $Script:Module = Import-Module $ENV:BHPSModuleManifest -Force -PassThru 9 | 10 | Describe 'Get-Module -Name PSTelegramAPI' { 11 | Context 'Strict mode' { 12 | 13 | Set-StrictMode -Version Latest 14 | 15 | It 'Should Import' { 16 | $Script:Module.Name | Should be $ENV:BHProjectName 17 | } 18 | It 'Should have ExportedFunctions' { 19 | $Script:Module.ExportedFunctions.Keys -contains 'Get-TLContacts' | Should be $True 20 | $Script:Module.ExportedFunctions.Keys -contains 'Get-TLHistory' | Should be $True 21 | $Script:Module.ExportedFunctions.Keys -contains 'Get-TLUserDialogs' | Should be $True 22 | $Script:Module.ExportedFunctions.Keys -contains 'Invoke-TLSendMessage' | Should be $True 23 | $Script:Module.ExportedFunctions.Keys -contains 'New-TLClient' | Should be $True 24 | } 25 | } 26 | } 27 | 28 | Describe 'Execute Function tests' { 29 | Context 'Strict mode' { 30 | 31 | Set-StrictMode -Version Latest 32 | 33 | $Invalid_ApiId = Get-Random -Minimum 100000 -Maximum 999999 34 | $Invalid_ApiHash = [guid]::NewGuid().Guid.Replace('-','') 35 | $Invalid_PhoneNumber = '15550000000' 36 | 37 | It 'New-TLClient: Should fail with invalid ApiId' { 38 | { New-TLClient -ApiId $Invalid_ApiId -ApiHash $Invalid_ApiHash -PhoneNumber $Invalid_PhoneNumber } | Should -Throw "API_ID_INVALID" 39 | } 40 | It 'New-TLClient: Should fail with invalid ApiHash' { 41 | { New-TLClient -ApiId $ENV:TLApiId -ApiHash $Invalid_ApiHash -PhoneNumber $Invalid_PhoneNumber } | Should -Throw "API_ID_INVALID" 42 | } 43 | It 'New-TLClient: Should prompt for Code' { 44 | Mock 'Read-Host' { 11111 } -ModuleName PSTelegramAPI 45 | { New-TLClient -ApiId $ENV:TLApiId -ApiHash $ENV:TLApiHash -PhoneNumber $Invalid_PhoneNumber } | Should -Throw "The numeric code used to authenticate does not match the numeric code sent by SMS/Telegram" 46 | Assert-MockCalled -CommandName Read-Host -ModuleName PSTelegramAPI -Exactly 1 47 | } 48 | } 49 | } 50 | 51 | Describe 'Execution End-to-End tests' { 52 | Context 'Strict mode' { 53 | Set-StrictMode -Version Latest 54 | 55 | It 'New-TLClient: Should be IsConnected' -Skip { 56 | $Script:TLClient = New-TLClient -ApiId $ENV:TLApiId -ApiHash $ENV:TLApiHash -PhoneNumber $ENV:TLPhoneNumber 57 | $Script:TLClient.IsUserAuthorized() | Should -Be $true 58 | } 59 | 60 | It 'Get-TLContacts: Should be TLContacts' -Skip { 61 | $Script:TLContacts = Get-TLContacts -TLClient $Script:TLClient 62 | $Script:TLContacts.GetType().Name | Should -Be 'TLContacts' 63 | } 64 | 65 | It 'Get-TLUserDialogs: Should contain TLUserDialog' -Skip { 66 | $Script:TLUserDialogs = Get-TLUserDialogs -TLClient $Script:TLClient 67 | $Script:TLUserDialogs.Constructor | Should -Contain '1728035348' 68 | } 69 | 70 | It 'Get-TLUserDialogs: Should contain TLUser' -Skip { 71 | $Script:TLPeer = $Script:TLUserDialogs.Where({$_.Peer.username -eq 'mkellerman'}).Peer 72 | $Script:TLPeer.GetType().Name | Should -Be 'TLUser' 73 | } 74 | 75 | It 'Get-TLUserDialogs: Should contain TLMessage' -Skip { 76 | $Script:TLMessage = $Script:TLUserDialogs.Where({$_.Peer.username -eq 'mkellerman'}).Message 77 | $Script:TLMessage.GetType().Name | Should -Be 'TLMessage' 78 | } 79 | 80 | It 'Get-TLHistory: Should contain TLMessage' -Skip { 81 | $Script:TLHistory = Get-TLHistory -TLClient $Script:TLClient -TLPeer $Script:TLPeer -Limit 1 82 | $Script:TLHistory.Messages[0].GetType().Name | Should -Be 'TLMessage' 83 | } 84 | 85 | It 'Invoke-TLSendMessage: Should contain TLUpdateShortSentMessage' -Skip { 86 | $Script:TLSendMessage = Invoke-TLSendMessage -TLClient $Script:TLClient -TLPeer $Script:TLPeer -Message "Pester Test ${ENV:BHBuildNumber}" 87 | } 88 | 89 | } 90 | } -------------------------------------------------------------------------------- /azure-pipelines.yml: -------------------------------------------------------------------------------- 1 | name: $(Build.DefinitionName)_$(Date:yyyyMMdd) 2 | 3 | resources: 4 | - repo: self 5 | 6 | queue: 7 | name: Hosted VS2017 8 | 9 | steps: 10 | - powershell: './PSTelegramAPI.bootstrap.ps1' 11 | displayName: 'Invoke Bootstrap' 12 | 13 | - powershell: 'Invoke-Build -Configuration Production -Task Test' 14 | displayName: 'Invoke Pester Tests' 15 | 16 | - task: PublishTestResults@2 17 | displayName: 'Publish Test Results' 18 | inputs: 19 | testResultsFormat: NUnit 20 | testResultsFiles: 'TestResults-*.xml' 21 | searchFolder: '$(System.DefaultWorkingDirectory)/TestResults' 22 | 23 | - task: PublishCodeCoverageResults@1 24 | displayName: 'Publish Code Coverage' 25 | inputs: 26 | summaryFileLocation: '$(System.DefaultWorkingDirectory)/TestResults/CodeCoverage-*.xml' 27 | reportDirectory: '$(System.DefaultWorkingDirectory)/TestResults' 28 | 29 | - task: PublishBuildArtifacts@1 30 | displayName: 'Publish Artifact: PSTelegramAPI' 31 | inputs: 32 | PathtoPublish: '$(System.DefaultWorkingDirectory)/PSTelegramAPI' 33 | ArtifactName: PSTelegramAPI 34 | 35 | - powershell: 'Invoke-Build -Configuration Production -Task UpdateManifest, PublishModule' 36 | displayName: 'Publish PowerShell Module' --------------------------------------------------------------------------------