5
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

PowerShell スクリプトで UUID v5 を生成する

Posted at

はじめに

先日、とある業務中に「 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 。
    • 一意であることが保証されているバイト列をハッシュ化して生成される。
    • 同じバイト列からは同じ UUID が生成される。
    • このバイト列は名前空間 (namespace) + 名前 (name) の組み合わせから構成されるため、この2つを組み合わせたものが一意である必要がある。
    • v3 はハッシュ化アルゴリズムに MD5 を、 v5 は SHA-1 を使用する。

といったものです。

以下が今回書いた PowerShell スクリプトです。

スクリプト

generateUUIDv5.ps1
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 を読んだりと楽しんで書くことができました。

とてもニッチな小ネタですが、どなたかのお役に立てば幸いです。

  1. 引数-nameに与える文字列のエンコードがUTF-8でない場合、期待した結果と異なる結果になることがあります。

5
5
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
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?