# Download one report as JSON and CSV. # Works in Windows PowerShell 5.1 and PowerShell 7. $ErrorActionPreference = 'Stop' # Your portal address and the report to download. $BaseUrl = 'https://reports.example.com/yourcompany' $Report = 'AdminChargeDetail' # The folder the JSON and CSV files are saved in. The default is a Reports # folder in your Documents folder. To use another folder, replace the line # with its full path in single quotes, for example: # $OutDir = 'D:\Finance\Reports' $OutDir = Join-Path ([Environment]::GetFolderPath('MyDocuments')) 'Reports' # Where step 1 saved your credentials. Leave this as it is. $CredDir = Join-Path $env:USERPROFILE '.report-api' # Older Windows PowerShell setups may not offer TLS 1.2 unless asked. [Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12 # Windows PowerShell 5.1 slows large downloads badly while it draws a # progress bar. The script prints its own messages instead. $ProgressPreference = 'SilentlyContinue' $Invariant = [Globalization.CultureInfo]::InvariantCulture $Utf8NoBom = New-Object System.Text.UTF8Encoding $false $Utf8Bom = New-Object System.Text.UTF8Encoding $true # One CSV cell: nested values as JSON text, dates as ISO text, # numbers with a "." decimal point whatever the machine's language. function Format-Cell($Value) { if ($null -eq $Value) { return '' } if ($Value -is [string]) { return $Value } if ($Value -is [bool]) { return $Value.ToString().ToLowerInvariant() } if ($Value -is [datetime]) { return $Value.ToString('yyyy-MM-ddTHH:mm:ss.FFFFFFF', $Invariant) } if ($Value -is [System.Management.Automation.PSCustomObject] -or $Value -is [System.Collections.IEnumerable]) { return (ConvertTo-Json -InputObject $Value -Compress -Depth 20) } if ($Value -is [IFormattable]) { return $Value.ToString($null, $Invariant) } return "$Value" } $credential = Import-Clixml (Join-Path $CredDir 'credential.xml') New-Item -ItemType Directory -Force -Path $OutDir | Out-Null $raw = Join-Path $OutDir "$Report.raw.json" $session = $null try { $body = @{ user_name = $credential.UserName password = $credential.GetNetworkCredential().Password } | ConvertTo-Json -Compress Write-Host "Signing in to $BaseUrl" try { Invoke-RestMethod -Method Post -Uri "$BaseUrl/api/login" -UseBasicParsing ` -ContentType 'application/json' -Body $body ` -SessionVariable session | Out-Null } catch { throw "Sign-in failed: $($_.Exception.Message)" } finally { Remove-Variable body -ErrorAction SilentlyContinue } # Save the response as received, then read it as UTF-8. The server does # not name a character set, and Windows PowerShell 5.1 would otherwise # misread accented characters. Write-Host "Downloading the $Report report. A large report can take several" Write-Host "minutes, and nothing more is shown until it finishes." Invoke-RestMethod -Uri "$BaseUrl/api/report/$Report" -UseBasicParsing ` -WebSession $session -OutFile $raw $rows = @((Get-Content -Path $raw -Raw -Encoding UTF8 | ConvertFrom-Json).d) $json = Join-Path $OutDir "$Report.json" $jsonText = ConvertTo-Json -InputObject $rows -Depth 20 [IO.File]::WriteAllText($json, $jsonText, $Utf8NoBom) # The CSV starts with a UTF-8 byte-order mark so Excel reads accented # characters correctly. $csv = Join-Path $OutDir "$Report.csv" $csvText = '' if ($rows.Count -gt 0) { $columns = @($rows[0].PSObject.Properties.Name) $lines = $rows | ForEach-Object { $row = $_ $cells = [ordered]@{} foreach ($column in $columns) { $cells[$column] = Format-Cell $row.$column } [pscustomobject]$cells } | ConvertTo-Csv -NoTypeInformation $csvText = ($lines -join "`r`n") + "`r`n" } [IO.File]::WriteAllText($csv, $csvText, $Utf8Bom) Write-Output "Saved $json and $csv" } finally { if ($session) { try { Invoke-RestMethod -Uri "$BaseUrl/api/logout" -UseBasicParsing ` -WebSession $session | Out-Null } catch { } } Remove-Item -Path $raw -ErrorAction SilentlyContinue }