在 PowerShell 要爬網站或存取網頁,Invoke-WebRequest 是不二選擇。有時我們會存取具有 Session 狀態的網頁,例如:要先登入後才能存取某些功能、或在 A 網頁儲存設定後到 B 網頁看結果。實務上 Session 概念多半依賴 Cookie 實現 (相關原理可參考 再探 ASP.NET 大排長龍問題的實驗觀察,ASP.NET 用到 Session 物件時寫入 ASP.NET_Session_Id),換言之,只要在送出 HTTP Request 正確附加 Cookie,就可存取該 Session 的狀態。除了 Session 之外,登入身分也幾乎都是靠 Cookie 實現,透過編碼或加密過的識別字串,供伺服器端檢核及識別登入者。

HttpWebRequest 有個 CookieContainer 屬性做為儲存 Cookie 的容器,從頭到尾使用同一個 CookieContainer 存取不同網頁,CookieContainer 便會保留各網站寫入的 Cookie,後續存取時附上,實現像瀏覽器能記住登入身分或 Session 的效果。PowerShell Invoke-WebRequest 底層是用 HttpWebRequest 實做,自然也支援此一功能。

設計以下實驗驗證。寫一個超簡單的 ASP.NET 網頁存入 Session 變數並導向另一個顯示 Session 變數內容的頁面:(SaveSession.aspx)

<%@Page Language="C#"%>
<script runat="server">
void Page_Load(object sender, EventArgs e)
{
	if (string.IsNullOrEmpty(Request["s"])) 
		Response.Write("Invalid Request");
	else 
	{
		Session["State"] = Request["s"];
		Response.Redirect("ShowSession.aspx");
	}
}
</script>

顯示 Session 變數的程式如下:(ShowSession.aspx)

<%@Page Language="C#"%>
<script runat="server">
void Page_Load(object sender, EventArgs e)
{
	Response.Write("Session=" + (Session["State"] ?? "NA"));
}
</script>

一般 Invoke-WebRequest 是不會記憶 Cookie 的,因此,呼叫 SaveSession.aspx 直接被導向 ShowSession.aspx 因為 Cookie 剛寫入有帶入,能正確顯示 Session 變數內容。但再次呼叫 ShowSession.aspx 時,並未附上剛才寫入的 Cookie,看不到剛才的 Session 變數。

# Invoke-WebRequest 預設不會記憶 Cookie / Session
(Invoke-WebRequest -Uri http://localhost/aspnet/sessiondemo/savesession.aspx?s=Jeffrey).Content
(Invoke-WebRequest -Uri http://localhost/aspnet/sessiondemo/showsession.aspx).Content

Invoke-WebRequest 有個 -SessionVariable 及 -WebSession 參數,第一次使用時寫 -SessionVariable 變數名稱(注意,不用加 $ 符號),之後 Invoke-WebRequest 時加上 -WebSession $變數名稱 (注意:要加 $),就可以沿用 Cookie 了。「$變數名稱」會是一個 WebRequestSession 物件,其中的 Cookie 屬性就是 Sysetm.Net.CookieContainer:

# 使用 -SessionVariable 建立 WebRequestSession 物件,注意變數名稱前方不用加 $
(Invoke-WebRequest -Uri http://localhost/aspnet/sessiondemo/savesession.aspx?s=Jeffrey -SessionVariable Sess).Content
# 後續使用 -WebSession 帶入 WebRequestSession 物件,可保存 Cookie 狀態,對映 ASP.NET Session
(Invoke-WebRequest -Uri http://localhost/aspnet/sessiondemo/showsession.aspx -WebSession $Sess).Content
# 不帶入 -WebSession 則無法取得 ASP.NET Session 資料
(Invoke-WebRequest -Uri http://localhost/aspnet/sessiondemo/showsession.aspx).Content

Tips of how to use Invoke-WebRequest to read stateful web pages in PowerShell.


Comments

Be the first to post a comment

Post a comment