param( [string]$BaseUrl = 'http://localhost:5099', [string]$AdminUsername = $env:Admin__Username, [string]$AdminPassword = $env:Admin__Password ) $ErrorActionPreference = 'Stop' Add-Type -AssemblyName System.Net.Http if ([string]::IsNullOrWhiteSpace($AdminUsername) -or [string]::IsNullOrWhiteSpace($AdminPassword)) { throw 'Admin__Username and Admin__Password must be provided.' } $stamp = Get-Date -Format 'yyyyMMddHHmmss' $actorUsername = "adminsmoke$stamp" $targetUsername = "adminpeer$stamp" $password = 'Demo123!' $attachmentName = "admin-attachment-$stamp.txt" $actorPhone = "+7911$stamp" $targetPhone = "+7922$stamp" $actorSession = Invoke-RestMethod ` -Uri "$BaseUrl/api/auth/register" ` -Method Post ` -ContentType 'application/json' ` -Body (@{ username = $actorUsername displayName = 'Admin Smoke Actor' password = $password phoneNumber = $actorPhone } | ConvertTo-Json) $targetSession = Invoke-RestMethod ` -Uri "$BaseUrl/api/auth/register" ` -Method Post ` -ContentType 'application/json' ` -Body (@{ username = $targetUsername displayName = 'Admin Smoke Peer' password = $password phoneNumber = $targetPhone } | ConvertTo-Json) $actorHeaders = @{ Authorization = "Bearer $($actorSession.accessToken)" } $targetUser = Invoke-RestMethod ` -Uri "$BaseUrl/api/users/search?q=$targetUsername" ` -Headers $actorHeaders ` -Method Get | Select-Object -First 1 $chat = Invoke-RestMethod ` -Uri "$BaseUrl/api/chats/direct" ` -Headers $actorHeaders ` -Method Post ` -ContentType 'application/json' ` -Body (@{ userId = $targetUser.id } | ConvertTo-Json) $tempFile = Join-Path $env:TEMP $attachmentName "admin attachment smoke $stamp" | Set-Content -Path $tempFile -NoNewline $handler = New-Object System.Net.Http.HttpClientHandler $client = New-Object System.Net.Http.HttpClient($handler) $client.BaseAddress = [Uri]::new("$BaseUrl/") $client.DefaultRequestHeaders.Authorization = New-Object System.Net.Http.Headers.AuthenticationHeaderValue('Bearer', $actorSession.accessToken) $form = New-Object System.Net.Http.MultipartFormDataContent $form.Add((New-Object System.Net.Http.StringContent('admin smoke attachment')), 'text') $fileStream = [System.IO.File]::OpenRead($tempFile) $fileContent = New-Object System.Net.Http.StreamContent($fileStream) $fileContent.Headers.ContentType = New-Object System.Net.Http.Headers.MediaTypeHeaderValue('text/plain') $form.Add($fileContent, 'file', [System.IO.Path]::GetFileName($tempFile)) $uploadResponse = $client.PostAsync("api/chats/$($chat.id)/attachments", $form).GetAwaiter().GetResult() $uploadPayload = $uploadResponse.Content.ReadAsStringAsync().GetAwaiter().GetResult() $fileStream.Dispose() $form.Dispose() $client.Dispose() $handler.Dispose() if (-not $uploadResponse.IsSuccessStatusCode) { throw $uploadPayload } $uploadedMessage = $uploadPayload | ConvertFrom-Json $attachment = $uploadedMessage.attachments[0] $adminSession = New-Object Microsoft.PowerShell.Commands.WebRequestSession Invoke-RestMethod ` -Uri "$BaseUrl/admin/api/session/login" ` -WebSession $adminSession ` -Method Post ` -ContentType 'application/json' ` -Body (@{ username = $AdminUsername password = $AdminPassword } | ConvertTo-Json) | Out-Null $status = Invoke-RestMethod ` -Uri "$BaseUrl/admin/api/status" ` -WebSession $adminSession ` -Method Get $usersBeforeDeleteResponse = Invoke-RestMethod ` -Uri "$BaseUrl/admin/api/users?q=adminsmoke$stamp" ` -WebSession $adminSession ` -Method Get [object[]]$usersBeforeDelete = if ($null -eq $usersBeforeDeleteResponse) { @() } else { @($usersBeforeDeleteResponse) } $chatsBeforeDeleteResponse = Invoke-RestMethod ` -Uri "$BaseUrl/admin/api/chats?q=adminsmoke$stamp" ` -WebSession $adminSession ` -Method Get [object[]]$chatsBeforeDelete = if ($null -eq $chatsBeforeDeleteResponse) { @() } else { @($chatsBeforeDeleteResponse) } $attachmentsBeforeDeleteResponse = Invoke-RestMethod ` -Uri "$BaseUrl/admin/api/attachments?q=$attachmentName" ` -WebSession $adminSession ` -Method Get [object[]]$attachmentsBeforeDelete = if ($null -eq $attachmentsBeforeDeleteResponse) { @() } else { @($attachmentsBeforeDeleteResponse) } $downloadPath = Join-Path $env:TEMP "admin-download-$stamp.txt" Invoke-WebRequest ` -Uri "$BaseUrl/admin/api/attachments/$($attachment.id)/content" ` -WebSession $adminSession ` -OutFile $downloadPath | Out-Null Invoke-RestMethod ` -Uri "$BaseUrl/admin/api/users/$($actorSession.user.id)/block" ` -WebSession $adminSession ` -Method Post | Out-Null $blockedStatusCode = 0 try { Invoke-WebRequest ` -Uri "$BaseUrl/api/auth/login" ` -Method Post ` -ContentType 'application/json' ` -Body (@{ username = $actorUsername password = $password } | ConvertTo-Json) | Out-Null } catch { $blockedStatusCode = [int]$_.Exception.Response.StatusCode } Invoke-RestMethod ` -Uri "$BaseUrl/admin/api/users/$($actorSession.user.id)/unblock" ` -WebSession $adminSession ` -Method Post | Out-Null $actorSessionAfterUnblock = Invoke-RestMethod ` -Uri "$BaseUrl/api/auth/login" ` -Method Post ` -ContentType 'application/json' ` -Body (@{ username = $actorUsername password = $password } | ConvertTo-Json) $actorHeadersAfterUnblock = @{ Authorization = "Bearer $($actorSessionAfterUnblock.accessToken)" } Invoke-RestMethod ` -Uri "$BaseUrl/admin/api/chats/$($chat.id)" ` -WebSession $adminSession ` -Method Delete | Out-Null $chatDeleted = $false try { Invoke-RestMethod ` -Uri "$BaseUrl/api/chats/$($chat.id)" ` -Headers $actorHeadersAfterUnblock ` -Method Get | Out-Null } catch { $chatDeleted = [int]$_.Exception.Response.StatusCode -eq 404 } Invoke-RestMethod ` -Uri "$BaseUrl/admin/api/users/$($actorSession.user.id)" ` -WebSession $adminSession ` -Method Delete | Out-Null Invoke-RestMethod ` -Uri "$BaseUrl/admin/api/users/$($targetSession.user.id)" ` -WebSession $adminSession ` -Method Delete | Out-Null $usersAfterDeleteResponse = Invoke-RestMethod ` -Uri "$BaseUrl/admin/api/users?q=adminsmoke$stamp" ` -WebSession $adminSession ` -Method Get [object[]]$usersAfterDelete = if ($null -eq $usersAfterDeleteResponse) { @() } else { @($usersAfterDeleteResponse) } Invoke-RestMethod ` -Uri "$BaseUrl/admin/api/session/logout" ` -WebSession $adminSession ` -Method Post | Out-Null $logoutBlocked = $false try { Invoke-WebRequest ` -Uri "$BaseUrl/admin/api/status" ` -WebSession $adminSession ` -Method Get | Out-Null } catch { $logoutBlocked = [int]$_.Exception.Response.StatusCode -eq 401 } [pscustomobject]@{ ActorUsername = $actorUsername TargetUsername = $targetUsername TotalUsers = $status.totalUsers DatabaseReachable = $status.databaseReachable UsersBeforeCount = $usersBeforeDelete.Count ChatsBeforeCount = $chatsBeforeDelete.Count AttachmentsBeforeCount = $attachmentsBeforeDelete.Count UsersListed = $usersBeforeDelete.Count -ge 1 ChatsListed = $chatsBeforeDelete.Count -ge 1 AttachmentsListed = $attachmentsBeforeDelete.Count -ge 1 AttachmentDownloaded = (Get-Item $downloadPath).Length -gt 0 BlockedLoginStatus = $blockedStatusCode ChatDeleted = $chatDeleted UsersDeleted = $usersAfterDelete.Count -eq 0 AdminLogoutBlocked = $logoutBlocked }