URI(URL)を扱う場合URIクラスを使うと便利です。
URIからホスト名やパスなどを個別に取り出したり出来るので、どのようなプロパティがあるか実際に試してみました。
<#
.SYNOPSIS
URIオブジェクト
.DESCRIPTION
説明
#>
param (
[string]$Uri = "https://maywork.net/test/ua.php"
)
function Main
{
param (
$uriStr
)
$uri = [URI]::new($uriStr)
Write-Host "Uriオブジェクトのプロパティ一覧"
Write-Host "-------------------------------"
Write-Host ("AbsolutePath:{0}" -f $uri.AbsolutePath)
# AbsolutePath:/test/ua.php
Write-Host ("AbsoluteUri:{0}" -f $uri.AbsoluteUri)
# AbsoluteUri:https://maywork.net/test/ua.php
Write-Host ("Authority:{0}" -f $uri.Authority)
# Authority:maywork.net
Write-Host ("DnsSafeHost:{0}" -f $uri.DnsSafeHost)
# DnsSafeHost:maywork.net
Write-Host ("Fragment:{0}" -f $uri.Fragment)
# Fragment:
Write-Host ("Host:{0}" -f $uri.Host)
# Host:maywork.net
Write-Host ("HostNameType:{0}" -f $uri.HostNameType)
# HostNameType:Dns
Write-Host ("IdnHost:{0}" -f $uri.IdnHost)
# IdnHost:maywork.net
Write-Host ("IsAbsoluteUri:{0}" -f $uri.IsAbsoluteUri)
# IsAbsoluteUri:True
Write-Host ("IsDefaultPort:{0}" -f $uri.IsDefaultPort)
# IsDefaultPort:True
Write-Host ("IsFile:{0}" -f $uri.IsFile)
# IsFile:False
Write-Host ("IsLoopback:{0}" -f $uri.IsLoopback)
# IsLoopback:False
Write-Host ("IsUnc:{0}" -f $uri.IsUnc)
# IsUnc:False
Write-Host ("LocalPath:{0}" -f $uri.LocalPath)
# LocalPath:/test/ua.php
Write-Host ("OriginalString:{0}" -f $uri.OriginalString)
# OriginalString:https://maywork.net/test/ua.php
Write-Host ("PathAndQuery:{0}" -f $uri.PathAndQuery)
# PathAndQuery:/test/ua.php
Write-Host ("Port:{0}" -f $uri.Port)
# Port:443
Write-Host ("Query:{0}" -f $uri.Query)
# Query:
Write-Host ("Scheme:{0}" -f $uri.Scheme)
# Scheme:https
Write-Host ("Segments:{0}" -f $uri.Segments)
# Segments:/
Write-Host ("UserEscaped:{0}" -f $uri.UserEscaped)
# UserEscaped:False
Write-Host ("UserInfo:{0}" -f $uri.UserInfo)
# UserInfo:
}
Main $Uri
結構沢山プロパティがあります。
今回Webサイトをダウンロードしてローカルに保存する機能を作りたいと考えているのですが、ローカルに保存するパスをURIアドレスからホスト名+パス+クエリにしたいと思います。
ポートやユーザーはあまりお目にかかることが無いです。スキーマやフラグメントなどは盛り込もうとすると面倒なので割愛します。
この場合使えそうなプロパティは、
ホスト名
$uri.Host
パス+クエリ
$uri.PathAndQuery
になります。PathとQueryを別々に取得することもできますが、PathAndQueryを使うとひと手間減らすことが出来ます。
これを踏まえたてURIの文字列からローカルの保存先のパスを生成する関数を作ってみます。
<#
.SYNOPSIS
URIからローカルパスを生成
.DESCRIPTION
説明
#>
param (
[string]$Uri = "https://maywork.net/test/ua.php",
[string]$RootDir = ""
)
function Convert-URItoLcoalPath
{
param (
$uriStr,
$rootDir
)
$uri = [URI]::new($uriStr)
$HostPathAndQuer = $uri.Host + $uri.PathAndQuery
$outPath = Join-Path $rootDir $HostPathAndQuer
$outPath
}
if ($RootDir -eq "")
{
$RootDir = Join-Path ([Environment]::GetFolderPath("MyDocuments")) "web"
}
Convert-URItoLcoalPath $Uri $RootDir
# C:\Users\karet\Documents\web\maywork.net\test\ua.php
URIからそのままローカルパスを生成すると、Windowsのディレクトリ名やファイル名に使えない文字が含まれる可能性があります。
その対応をしたいと思います。
Windowsのファイル名に使えない文字
\/:*?”><|
\/はWindowsでもパスの区切り文字ですのでケアする必要はなさそうです。
それ以外は特別な意味があり、パス中に存在するのはNGになります。
:ドライブレターの区切り文字
?任意の一文字を表す特殊記号
*任意の文字列を表す特殊記号
<>|はパイプやリダイレクト
”もダメです。文字列を表す区切り文字だからでしょうか?ちなみに’はOKです
使えない文字を何か別の文字に代替する必要があります。
今回はregex.replaceの置換機能で該当文字をHttpUtility.UrlEncodeでエンコードし置換することにします。
また、パスにファイル名が含まれていない場合、ローカルではディレクトリを指すパスになりすが、webサイトの場合ファイル名を省略したwebページと解釈されるケースが多いです。
今回はデフォルトファイル名としてindex.htmlを補完します。
拡張子が無い場合ローカルではファイルタイプが不明となり都合が悪いので.htmlを補います。
<#
.SYNOPSIS
URIからローカルパスを生成
.DESCRIPTION
説明
#>
using namespace System.Web
using namespace System.IO
param (
[string]$Uri = "https://maywork.net/test/ngword""?|",
[string]$RootDir = ""
)
function Convert-URItoLcoalPath
{
param (
$uriStr,
$rootDir
)
$uri = [URI]::new($uriStr)
$HostPathAndQuer = $uri.Host + $uri.PathAndQuery
# エンコード
$pattern = "[:""\*\?\<\>\|]"
$HostPathAndQuer = [regex]::replace($HostPathAndQuer, $pattern, { [HttpUtility]::UrlEncode($args.value) })
# 末尾が/の場合
if ("/" -eq $HostPathAndQuer.Substring($HostPathAndQuer.Length - 1, 1))
{
$HostPathAndQuer = $HostPathAndQuer + "index.html"
}
$outPath = Join-Path $rootDir $HostPathAndQuer
# 拡張子がない場合
if ([Path]::GetExtension($outPath) -eq "")
{
$outPath = $outPath + ".html"
}
$outPath
}
if ($RootDir -eq "")
{
$RootDir = Join-Path ([Environment]::GetFolderPath("MyDocuments")) "web"
}
Convert-URItoLcoalPath $Uri $RootDir
# C:\Users\karet\Documents\web\maywork.net\test\ngword%22%3f%7C.html
試してみて気が付いたのですがUrlEncodeで*はエンコードしてくれないようです。
個別対応が必要ですが、*が含まれるURIを見たことが無いのでそのままにしておきます。
コメント