5
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

PowerShellでHTTPサーバを書いた

Last updated at Posted at 2021-09-07

処理の概要

  1. PowerShellから.NET C#のSystem.Net.HttpListenerクラスを呼び出し
    ローカルホストとのHTTP通信を行う
  2. 下記のPowerShellファイルは、Webサイトのルートフォルダに配置されている
    想定で作られている
  3. http://localhost:<ポート番号>/でホームページとなるindex.htmlファイルが開く
  4. HTML内の内容から、CSS、JavaScript、画像などのファイルを追加で送信可能

動作の前提

Webページのルートフォルダに配置して使う

ソースコード

server.ps1
# ポート番号
$Port = "8080"
# URL
$url = "http://localhost:" + $Port + "/"
# localhostに繋げない環境への対応
# $url = "http://+:" + $Port + "/Temporary_Listen_Addresses/"
# リクエストがルート(/)の場合、呼び出されるファイル
$HomePage = "index.html"
# コンテンツタイプ辞書(ブラウザに送るデータの種類)
$ContentType = @{
    "css" = "text/css"
    "js" = "application/javascript"
    "json" = "application/json"
    "html" = "text/html"
    "pdf" = "application/pdf"
    "txt" = "text/plain"
    "jpg" = "image/jpeg"
    "png" = "image/png"
    "xml" = "application/xml"
    "*" = "application/octet-stream"
}

# リクエストがなくなるまでファイル送信を行う
function fileSendToClient([ref]$response, $fileName) {
    $currentDirectory = Convert-Path .
    $fullPath = Join-Path $currentDirectory $fileName
    if ([IO.File]::Exists($fullPath)) {
        # 要求されたファイル名が実際に存在する場合
        $extension = $(Get-Item $fullPath).Extension.Replace(".", "")
        if ($ContentType.ContainsKey($extension)) {
            # 拡張子が事前定義したコンテンツタイプ辞書にある場合
            $response.Value.ContentType = $ContentType[$extension]
        } else {
            # コンテンツタイプが拡張子から特定できない場合、octet-streamをセット
            $response.Value.ContentType = $ContentType["*"]
        }
        $response.Value.ContentType += ";charset=UTF-8"
        $content = [IO.File]::ReadAllBytes($fullPath)
        $response.Value.ContentLength64 = $content.Length
        $output = $response.Value.OutputStream
        $output.Write($content, 0, $content.Length)
        $output.Close()
    } else {
        $response.Value.StatusCode = 404
    }
}

function main {
    $listener = New-Object Net.HttpListener
    $listener.Prefixes.Add($url)
    Write-Output "* Running on $url (Press CTRL+C to quit)"

    try {
        $listener.Start()
        while ($listener.IsListening) {
            $task = $listener.GetContextAsync()

            # Ctrl+Cを機能させる処理
            while ($task.AsyncWaitHandle.WaitOne(500) -eq $false) {}

            $context = $task.GetAwaiter().GetResult()
            If ($page = $context.Request.Url.LocalPath -eq "/") {
                # 最初のページ送信
                $page = $HomePage
            } else {
                # CSS,Javascriptなどのファイルが要求された場合
                $page = $context.Request.RawUrl
            }
            $response = $context.Response
            If ($context.Request.IsLocal) {
                # ローカルPCからの接続の場合
                fileSendToClient ([ref]$response) $page
            }
            Write-Output $context.Request.RawUrl
            Write-Output $context.Response
            $response.Close()
        }
    } catch {
        Write-Error($_.Exception)
    } finally {
        $listener.Close()
    }
}

main
exit

感想

functionにC#クラスなどのオブジェクトを参照渡しして値を取り出そうとしたら、
引数名.Value.メソッド名と書かないといけないことに気付き、脳を破壊された。

function 関数名([ref]$引数名) { $引数名.Value.ByeByePowerShell }

参考記事

  1. PowerShellでHTTPサーバー的なものを作る
  2. 管理者権限のないプレーンなWindowsでWebサーバを立てる戦い
5
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?