[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" }