はじめに
先日、とある業務中に「 UUID v5 を生成する PowerShell スクリプト」を書く必要が生じました。
普通のランダムな UUID (UUID v4) であれば
[Guid]::NewGuid().ToString()
のように簡単に書くことができるのですが、ハッシュ値を使用する UUID v5 はググっても簡単な書き方はおろか、先例となるコードも見つけることができませんでした。
なので、自分で書くことにしました。
使用した環境は Windows 10 + PowerShell 7.3.3 です。
UUID v5 とは
詳しくは Wikipedia の記事などを読んでいただければと思いますが、簡単に概要を述べると、
- UUID (Universally Unique Identifier): 一意(ユニーク)であることが期待される識別子。32 桁の 16 進数と 4 つのハイフンで構成され、
xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
のような形式で表記される。 - 一般的によく見かける UUID は v4 。
- ランダム値をもとに生成される。
- Microsoft は GUID と呼んでいる。
- v3/5 はハッシュ値をもとにした UUID 。
といったものです。
以下が今回書いた PowerShell スクリプトです。
スクリプト
param(
[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[String]$namespace,
[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[String]$name
)
function swapUUIDByteArray([Array]$byteArray){
$resultArray = $byteArray
$temp = $resultArray[0]
$resultArray[0] = $resultArray[3]
$resultArray[3] = $temp
$temp = $resultArray[1]
$resultArray[1] = $resultArray[2]
$resultArray[2] = $temp
$temp = $resultArray[4]
$resultArray[4] = $resultArray[5]
$resultArray[5] = $temp
$temp = $resultArray[6]
$resultArray[6] = $resultArray[7]
$resultArray[7] = $temp
return $resultArray
}
function convertBytesToStr([Array]$bytes){
return [String](-join ($bytes | ForEach-Object { '{0:x2}' -f $_ }))
}
function convertUUIDBytesToStr([Array]$bytes){
return [String](convertBytesToStr $bytes[0..3]) +
"-" + (convertBytesToStr $bytes[4..5]) +
"-" + (convertBytesToStr $bytes[6..7]) +
"-" + (convertBytesToStr $bytes[8..9]) +
"-" + (convertBytesToStr $bytes[10..15])
}
function generateUUIDv5([Guid]$namespace, [String]$name){
$nsBytes = swapUUIDByteArray $namespace.ToByteArray() # Convert namespace uuid to network byte order.
$hasher = New-Object System.Security.Cryptography.SHA1CryptoServiceProvider
$bytes = $nsBytes + [Text.Encoding]::UTF8.GetBytes($name)
$hash = $hasher.ComputeHash($bytes)
$hash[6] = ($hash[6] -band 0x0F) -bor 0x50 # Embed version bits.
$hash[8] = ($hash[8] -band 0x3F) -bor 0x80 # Embed variant bits.
$uuidStr = convertUUIDBytesToStr $hash
return [Guid]::new($uuidStr)
}
function generateUUIDv5Str([String]$namespace, [String]$name){
$namespaceUuid = [Guid]::new($namespace)
$uuid = generateUUIDv5 $namespaceUuid $name
return $uuid.ToString()
}
generateUUIDv5Str $namespace $name
使用法
上記のスクリプトを任意のディレクトリに generateUUIDv5.ps1
のような名前で保存してやり、
generateUUIDv5.ps1 -namespace 'cfbff0d1-9375-5685-968c-48ce8b15ae17' -name 'example'
のように呼んでやると、
0782cc7f-ce8d-528a-a980-9295f3abe079
のように UUID v5 が返ってきます1。
終わりに
今まで PowerShell スクリプトを書いたことがなかったために意外と苦戦しましたが、 UUID の RFC を読んだりと楽しんで書くことができました。
とてもニッチな小ネタですが、どなたかのお役に立てば幸いです。
-
引数
-name
に与える文字列のエンコードがUTF-8でない場合、期待した結果と異なる結果になることがあります。 ↩