[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Add-Type -AssemblyName System.Web
$utf8NoBom = New-Object System.Text.UTF8Encoding($false)
$BaseUrl = 'https://fukuchiyama-web.campusplan.jp/portal/'
$StartDate = '2025-09-22'
$EndDate = '2025-12-31'
$ApiUrl = 'https://www.48v.me/~7kasone/cgi-bin/zemi_course_take_list.py'
function ConvertFrom-SecureStringToPlain {
param([Parameter(Mandatory=$true)][Security.SecureString]$SecureString)
$bstr = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecureString)
try { [Runtime.InteropServices.Marshal]::PtrToStringAuto($bstr) } finally { [Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr) }
}
function Get-UserConfirmation {
$title = "Execution Confirmation"
$message = "This script will access the portal and send data to external API. Continue?"
$yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes", "Continue execution"
$no = New-Object System.Management.Automation.Host.ChoiceDescription "&No", "Cancel execution"
$opts = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no)
return $host.UI.PromptForChoice($title, $message, $opts, 1) -eq 0
}
function Write-Progress-Info { param([string]$Activity,[string]$Status) Write-Progress -Activity $Activity -Status $Status }
function Get-VerificationToken {
param([string]$Html)
$patterns = @(
']*name=["'']__RequestVerificationToken["''][^>]*value=["'']([^"'']+)["''][^>]*>',
']*value=["'']([^"'']+)["''][^>]*name=["'']__RequestVerificationToken["''][^>]*>'
)
foreach ($p in $patterns) { if ($Html -match $p) { return $Matches[1] } }
throw "RequestVerificationToken not found"
}
function Get-ClientTokenId {
param([string]$Html)
if ($Html -match 'var\s+_ClientTokenId\s*=\s*["'']([^"'']+)["'']') { return $Matches[1] }
throw "ClientTokenId not found"
}
function Get-AccessToken {
param([Microsoft.PowerShell.Commands.WebRequestSession]$Session,[string]$BaseUrl,[string]$ClientTokenId)
$authorizeUri = "$BaseUrl" + "Account/Authorize?client_id=$ClientTokenId&response_type=token&state="
$resp = Invoke-WebRequest -Uri $authorizeUri -WebSession $Session
$frag = $resp.BaseResponse.ResponseUri.Fragment.TrimStart('#')
$qs = [System.Web.HttpUtility]::ParseQueryString('?' + $frag)
$tok = $qs['access_token']
if (-not $tok) { throw "Access token not found" }
return $tok
}
function Get-CampusCalendarData {
param([Microsoft.PowerShell.Commands.WebRequestSession]$Session,[string]$BaseUrl,[string]$AccessToken,[string]$Start,[string]$End)
$headers = @{ 'Content-Type' = 'application/json; charset=utf-8'; 'X-CPAuthorize' = "Bearer $AccessToken" }
$apiUri = "$BaseUrl" + "api/KogiCalendar/?uKbn=1&start=$Start&end=$End"
Invoke-RestMethod -Uri $apiUri -Headers $headers -WebSession $Session -Method GET
}
function Show-CalendarSummary {
param([array]$CalendarData)
Write-Host "Calendar Data Summary:" -ForegroundColor Green
Write-Host ("Total entries: {0}" -f $CalendarData.Count) -ForegroundColor Yellow
if ($CalendarData.Count -gt 0) {
Write-Host "Sample entries:" -ForegroundColor Yellow
$CalendarData[0..([Math]::Min(2, $CalendarData.Count - 1))] | ForEach-Object {
Write-Host (" - {0} [{1} - {2}]" -f $_.title, $_.start, $_.end) -ForegroundColor Cyan
}
}
}
function Send-DataToApi {
param([string]$Email,[object]$Data,[string]$ApiUrl)
$uri = "$ApiUrl" + "?email=$([System.Web.HttpUtility]::UrlEncode($Email))"
$jsonData = $Data | ConvertTo-Json -Depth 8 -Compress
$utf8Bytes = $utf8NoBom.GetBytes($jsonData)
$req = [System.Net.HttpWebRequest]::Create($uri)
$req.Method = "POST"
$req.ContentType = "application/json; charset=utf-8"
$req.ContentLength = $utf8Bytes.Length
$req.UserAgent = "PowerShell/UTF8-Client"
try {
$rs = $req.GetRequestStream(); $rs.Write($utf8Bytes, 0, $utf8Bytes.Length); $rs.Close()
$resp = $req.GetResponse()
$stream = $resp.GetResponseStream()
$reader = [System.IO.StreamReader]::new($stream, [System.Text.Encoding]::UTF8)
$content = $reader.ReadToEnd()
$reader.Close(); $resp.Close()
$content | ConvertFrom-Json
} catch {
throw "API request failed: $($_.Exception.Message)"
}
}
try {
if (-not (Get-UserConfirmation)) { Write-Host "Execution cancelled by user." -ForegroundColor Red; return }
$secureUsername = Read-Host -AsSecureString -Prompt 'Username'
$securePassword = Read-Host -AsSecureString -Prompt 'Password'
$username = ConvertFrom-SecureStringToPlain -SecureString $secureUsername
$password = ConvertFrom-SecureStringToPlain -SecureString $securePassword
$email = "$username@fukuchiyama.ac.jp"
Write-Progress-Info "Portal Login" "Accessing login page"
$loginPage = Invoke-WebRequest -Uri ($BaseUrl + 'Account/Login') -SessionVariable session
$verificationToken = Get-VerificationToken -Html $loginPage.Content
Write-Progress-Info "Portal Login" "Submitting credentials"
$loginBody = @{ Username = $username; Password = $password; __RequestVerificationToken = $verificationToken }
$null = Invoke-WebRequest -Uri ($BaseUrl + 'Account/Login') -WebSession $session -Method POST -ContentType 'application/x-www-form-urlencoded' -Body $loginBody
Write-Progress-Info "Token Extraction" "Getting client token"
$portal = Invoke-WebRequest -Uri $BaseUrl -WebSession $session
$clientTokenId = Get-ClientTokenId -Html $portal.Content
Write-Progress-Info "Authorization" "Getting access token"
$accessToken = Get-AccessToken -Session $session -BaseUrl $BaseUrl -ClientTokenId $clientTokenId
Write-Progress-Info "Data Retrieval" "Fetching calendar data"
$calendarData = Get-CampusCalendarData -Session $session -BaseUrl $BaseUrl -AccessToken $accessToken -Start $StartDate -End $EndDate
Show-CalendarSummary -CalendarData $calendarData
Write-Progress-Info "API Submission" "Sending data to external API"
$apiResponse = Send-DataToApi -Email $email -Data $calendarData -ApiUrl $ApiUrl
Write-Host "API Response:" -ForegroundColor Green
$apiResponse | ConvertTo-Json -Depth 3 | Write-Host -ForegroundColor Cyan
Write-Host "Process completed successfully." -ForegroundColor Green
} catch {
Write-Host ("Error: {0}" -f $_.Exception.Message) -ForegroundColor Red
Write-Host ("Stack Trace: {0}" -f $_.ScriptStackTrace) -ForegroundColor Yellow
return
} finally {
Write-Progress -Completed -Activity "Complete"
}