Win32 API 日本語リファレンス
ホーム › Networking.ActiveDirectory › DsWriteAccountSpnW

DsWriteAccountSpnW

関数
アカウントオブジェクトにSPNを書き込む(Unicode版)。
DLLNTDSAPI.dll文字セットUnicode (-W)呼出規約winapi対応OSWindows Vista 以降

シグネチャ

// NTDSAPI.dll  (Unicode / -W)
#include <windows.h>

DWORD DsWriteAccountSpnW(
    HANDLE hDS,
    DS_SPN_WRITE_OP Operation,
    LPCWSTR pszAccount,
    DWORD cSpn,
    LPCWSTR* rpszSpn
);

パラメーター

名前型方向説明
hDSHANDLEinDSBind 関数または DSBindWithCred 関数から取得したディレクトリサービスハンドルを格納します。
OperationDS_SPN_WRITE_OPinDsWriteAccountSpn が実行する操作を指定する DS_SPN_WRITE_OP の値のいずれかを格納します。
pszAccountLPCWSTRinActive Directory Domain Services 内のユーザーオブジェクトまたはコンピューターオブジェクトの識別名を指定する、null で終わる定数文字列へのポインターです。呼び出し元は、このオブジェクトの servicePrincipalName プロパティへの書き込みアクセス権を持っている必要があります。
cSpnDWORDinrpszSpn に含まれる SPN の数を指定します。この値が 0 で、かつ Operation に DS_SPN_REPLACE_SPN_OP が含まれる場合、この関数は指定されたアカウントの servicePrincipalName 属性からすべての値を削除します。
rpszSpnLPCWSTR*inpszAccount パラメーターで識別されるアカウントに追加する、またはそのアカウントから削除する SPN を指定する、null で終わる定数文字列の配列へのポインターです。サービスの SPN を構成するには DsGetSpn 関数を使用します。

戻り値の型: DWORD

公式ドキュメント

Active Directory Domain Services 内の指定したユーザーアカウントオブジェクトまたはコンピューターアカウントオブジェクトの servicePrincipalName 属性に、サービスプリンシパル名 (SPN) の配列を書き込みます。(Unicode)

戻り値

成功した場合は ERROR_SUCCESS を返します。失敗した場合は、Win32、RPC、またはディレクトリサービスのエラーを返します。

解説(Remarks)

DsWriteAccountSpn 関数は、1 つ以上のサービスインスタンスの SPN を登録します。SPN は、信頼された認証サービスと組み合わせて、クライアントがサービスを認証するために使用します。アプリケーションやサービスが他のサービスを識別する SPN を不正に登録するセキュリティ攻撃を防ぐため、ユーザーアカウントおよびコンピューターアカウントの既定の DACL では、ほとんどの場合ドメイン管理者のみが SPN を登録できるようになっています。

このルールの例外の 1 つとして、LocalSystem アカウントで実行されているサービスは、SPN に指定されたホストが、そのサービスを実行しているコンピューターの DNS 名または NetBIOS 名である場合に限り、"ServiceClass/Host:Port" という形式の単純な SPN を DsWriteAccountSpn を呼び出して登録できます。

もう 1 つの例外として、コンピューターアカウントの既定の DACL では、一定の制約の下で、呼び出し元が自分自身に対して SPN を登録することが許可されています。たとえば、コンピューターアカウントは、自身のコンピューター名に基づく "host/<computername>" という形式の SPN を持つことができます。コンピューター名が SPN に含まれているため、この SPN は許可されます。

DSA が任意の SPN の書き込みを許可するように構成されている場合、上記のルールはいずれも適用されません。ただし、これはセキュリティを低下させるため推奨されません。

DsWriteAccountSpn に渡された SPN は、実際には pszAccount で指定されたコンピューターオブジェクトの Service-Principal-Name 属性に追加されます。この呼び出しは、アカウントオブジェクトが格納されているドメインコントローラーに対して RPC を使用して行われるため、そのアカウントで許可される SPN に関するポリシーを安全に適用できます。LDAP を使用して SPN プロパティに直接書き込むことは許可されておらず、すべての書き込みはこの RPC 呼び出しを経由する必要があります。LDAP を使用した読み取りは許可されています。

SPN の設定に必要なアクセス許可

アカウントに任意の SPN を書き込むには、書き込みを行う側に "Write ServicePrincipalName" 権限が必要ですが、この権限はアカウントを作成したユーザーには既定では付与されません。アカウントを作成したユーザーには "Write validated SPN" 権限 (マシンアカウントにのみ存在します) が付与されます。

以下は、マシンアカウントに対するユーザーごとの権限の概要です。

ユーザーの種類 権限
アカウントを作成したユーザー Write validated SPN
Account Operators Write SPN および Write Validated SPN
Authenticated Users なし
(自分自身) Write Validated SPN

ユーザーアカウントには "Validated SPN" プロパティも "Write SPN" 権限も存在しません。代わりに、"Write public information" プロパティセットによって、任意の SPN を作成する機能が付与されます。

メモ

ntdsapi.h ヘッダーは、UNICODE プリプロセッサ定数の定義に基づいて、この関数の ANSI 版または Unicode 版を自動的に選択するエイリアスとして DsWriteAccountSpn を定義します。エンコーディング中立のエイリアスと、エンコーディング中立でないコードを混在させて使用すると、不一致が生じ、コンパイルエラーや実行時エラーの原因となる可能性があります。詳細については、関数プロトタイプの規則を参照してください。

出典・ライセンス: 上記「公式ドキュメント」の内容は Microsoft の Win32 API ドキュメント(MicrosoftDocs/sdk-api)を日本語に翻訳・改変したものです。© Microsoft Corporation. CC BY 4.0 で提供。
Microsoft 公式リファレンス: 英語 (en-us) · 日本語 (ja-jp) · 原文ソース (GitHub)

各言語での呼び出し定義

// NTDSAPI.dll  (Unicode / -W)
#include <windows.h>

DWORD DsWriteAccountSpnW(
    HANDLE hDS,
    DS_SPN_WRITE_OP Operation,
    LPCWSTR pszAccount,
    DWORD cSpn,
    LPCWSTR* rpszSpn
);
[DllImport("NTDSAPI.dll", CharSet = CharSet.Unicode, ExactSpelling = true)]
static extern uint DsWriteAccountSpnW(
    IntPtr hDS,   // HANDLE
    int Operation,   // DS_SPN_WRITE_OP
    [MarshalAs(UnmanagedType.LPWStr)] string pszAccount,   // LPCWSTR
    uint cSpn,   // DWORD
    IntPtr rpszSpn   // LPCWSTR*
);
<DllImport("NTDSAPI.dll", CharSet:=CharSet.Unicode, ExactSpelling:=True)>
Public Shared Function DsWriteAccountSpnW(
    hDS As IntPtr,   ' HANDLE
    Operation As Integer,   ' DS_SPN_WRITE_OP
    <MarshalAs(UnmanagedType.LPWStr)> pszAccount As String,   ' LPCWSTR
    cSpn As UInteger,   ' DWORD
    rpszSpn As IntPtr   ' LPCWSTR*
) As UInteger
End Function
' hDS : HANDLE
' Operation : DS_SPN_WRITE_OP
' pszAccount : LPCWSTR
' cSpn : DWORD
' rpszSpn : LPCWSTR*
Declare PtrSafe Function DsWriteAccountSpnW Lib "ntdsapi" ( _
    ByVal hDS As LongPtr, _
    ByVal Operation As Long, _
    ByVal pszAccount As LongPtr, _
    ByVal cSpn As Long, _
    ByVal rpszSpn As LongPtr) As Long
' Unicode(W): 文字列は ByVal As LongPtr とし StrPtr(unicodeStr) を渡す
' VBA7前提(PtrSafe)。32bit Office では LongPtr→Long。Integer=16bit / Long=32bit / LongLong=64bit。
import ctypes
from ctypes import wintypes

DsWriteAccountSpnW = ctypes.windll.ntdsapi.DsWriteAccountSpnW
DsWriteAccountSpnW.restype = wintypes.DWORD
DsWriteAccountSpnW.argtypes = [
    wintypes.HANDLE,  # hDS : HANDLE
    ctypes.c_int,  # Operation : DS_SPN_WRITE_OP
    wintypes.LPCWSTR,  # pszAccount : LPCWSTR
    wintypes.DWORD,  # cSpn : DWORD
    ctypes.c_void_p,  # rpszSpn : LPCWSTR*
]
require 'fiddle'
require 'fiddle/import'

lib = Fiddle.dlopen('NTDSAPI.dll')
DsWriteAccountSpnW = Fiddle::Function.new(
  lib['DsWriteAccountSpnW'],
  [
    Fiddle::TYPE_VOIDP,  # hDS : HANDLE
    Fiddle::TYPE_INT,  # Operation : DS_SPN_WRITE_OP
    Fiddle::TYPE_VOIDP,  # pszAccount : LPCWSTR
    -Fiddle::TYPE_INT,  # cSpn : DWORD
    Fiddle::TYPE_VOIDP,  # rpszSpn : LPCWSTR*
  ],
  -Fiddle::TYPE_INT)
# Wide strings: pass str.encode("UTF-16LE") + "\x00\x00"
#[link(name = "ntdsapi")]
extern "system" {
    fn DsWriteAccountSpnW(
        hDS: *mut core::ffi::c_void,  // HANDLE
        Operation: i32,  // DS_SPN_WRITE_OP
        pszAccount: *const u16,  // LPCWSTR
        cSpn: u32,  // DWORD
        rpszSpn: *const *const u16  // LPCWSTR*
    ) -> u32;
}
// crates: windows-sys provides ready-made bindings for this API.
$sig = @"
[DllImport("NTDSAPI.dll", CharSet = CharSet.Unicode)]
public static extern uint DsWriteAccountSpnW(IntPtr hDS, int Operation, [MarshalAs(UnmanagedType.LPWStr)] string pszAccount, uint cSpn, IntPtr rpszSpn);
"@
$api = Add-Type -MemberDefinition $sig -Name 'NTDSAPI_DsWriteAccountSpnW' -Namespace Win32 -PassThru
# $api::DsWriteAccountSpnW(hDS, Operation, pszAccount, cSpn, rpszSpn)
#uselib "NTDSAPI.dll"
#func global DsWriteAccountSpnW "DsWriteAccountSpnW" wptr, wptr, wptr, wptr, wptr
; DsWriteAccountSpnW hDS, Operation, pszAccount, cSpn, varptr(rpszSpn)   ; 戻り値は stat
; hDS : HANDLE -> "wptr"
; Operation : DS_SPN_WRITE_OP -> "wptr"
; pszAccount : LPCWSTR -> "wptr"
; cSpn : DWORD -> "wptr"
; rpszSpn : LPCWSTR* -> "wptr"
; ※HSP3.7は #func のため戻り値はシステム変数 stat に格納されます。
出力引数:
#uselib "NTDSAPI.dll"
#cfunc global DsWriteAccountSpnW "DsWriteAccountSpnW" sptr, int, wstr, int, var
; res = DsWriteAccountSpnW(hDS, Operation, pszAccount, cSpn, rpszSpn)
; hDS : HANDLE -> "sptr"
; Operation : DS_SPN_WRITE_OP -> "int"
; pszAccount : LPCWSTR -> "wstr"
; cSpn : DWORD -> "int"
; rpszSpn : LPCWSTR* -> "var"
; ※出力/バッファ引数は var 方式(変数を直接渡す)。varptr 方式にも切替可。
出力引数:
; DWORD DsWriteAccountSpnW(HANDLE hDS, DS_SPN_WRITE_OP Operation, LPCWSTR pszAccount, DWORD cSpn, LPCWSTR* rpszSpn)
#uselib "NTDSAPI.dll"
#cfunc global DsWriteAccountSpnW "DsWriteAccountSpnW" intptr, int, wstr, int, var
; res = DsWriteAccountSpnW(hDS, Operation, pszAccount, cSpn, rpszSpn)
; hDS : HANDLE -> "intptr"
; Operation : DS_SPN_WRITE_OP -> "int"
; pszAccount : LPCWSTR -> "wstr"
; cSpn : DWORD -> "int"
; rpszSpn : LPCWSTR* -> "var"
; ※出力/バッファ引数は var 方式(変数を直接渡す)。varptr 方式にも切替可。
import (
	"golang.org/x/sys/windows"
	"unsafe"
)

var (
	ntdsapi = windows.NewLazySystemDLL("NTDSAPI.dll")
	procDsWriteAccountSpnW = ntdsapi.NewProc("DsWriteAccountSpnW")
)

// hDS (HANDLE), Operation (DS_SPN_WRITE_OP), pszAccount (LPCWSTR), cSpn (DWORD), rpszSpn (LPCWSTR*)
r1, _, err := procDsWriteAccountSpnW.Call(
	uintptr(hDS),
	uintptr(Operation),
	uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(pszAccount))),
	uintptr(cSpn),
	uintptr(rpszSpn),
)
_ = err  // syscall.Errno (valid when the call sets last-error)
_ = r1   // DWORD
function DsWriteAccountSpnW(
  hDS: THandle;   // HANDLE
  Operation: Integer;   // DS_SPN_WRITE_OP
  pszAccount: PWideChar;   // LPCWSTR
  cSpn: DWORD;   // DWORD
  rpszSpn: PPWideChar   // LPCWSTR*
): DWORD; stdcall;
  external 'NTDSAPI.dll' name 'DsWriteAccountSpnW';
result := DllCall("NTDSAPI\DsWriteAccountSpnW"
    , "Ptr", hDS   ; HANDLE
    , "Int", Operation   ; DS_SPN_WRITE_OP
    , "WStr", pszAccount   ; LPCWSTR
    , "UInt", cSpn   ; DWORD
    , "Ptr", rpszSpn   ; LPCWSTR*
    , "UInt")   ; return: DWORD
●DsWriteAccountSpnW(hDS, Operation, pszAccount, cSpn, rpszSpn) = DLL("NTDSAPI.dll", "dword DsWriteAccountSpnW(void*, int, char*, dword, void*)")
# 呼び出し: DsWriteAccountSpnW(hDS, Operation, pszAccount, cSpn, rpszSpn)
# hDS : HANDLE -> "void*"
# Operation : DS_SPN_WRITE_OP -> "int"
# pszAccount : LPCWSTR -> "char*"
# cSpn : DWORD -> "dword"
# rpszSpn : LPCWSTR* -> "void*"
# なでしこ1は32bit・ANSI(Shift_JIS)。文字列=char*(ANSI)、ポインタ/ハンドル=void*(4byte)。
# ※-W(Unicode)関数。なでしこ1はANSIのため -A 版の利用を推奨。
const std = @import("std");

extern "ntdsapi" fn DsWriteAccountSpnW(
    hDS: ?*anyopaque, // HANDLE
    Operation: i32, // DS_SPN_WRITE_OP
    pszAccount: [*c]const u16, // LPCWSTR
    cSpn: u32, // DWORD
    rpszSpn: [*c][*c]u16 // LPCWSTR*
) callconv(std.os.windows.WINAPI) u32;
// Unicode(-W): UTF-16LE のヌル終端バッファ([*c]const u16)を渡す。
proc DsWriteAccountSpnW(
    hDS: pointer,  # HANDLE
    Operation: int32,  # DS_SPN_WRITE_OP
    pszAccount: WideCString,  # LPCWSTR
    cSpn: uint32,  # DWORD
    rpszSpn: ptr WideCString  # LPCWSTR*
): uint32 {.importc: "DsWriteAccountSpnW", stdcall, dynlib: "NTDSAPI.dll".}
# Unicode(-W): WideCString は newWideCString("...") で生成。
pragma(lib, "ntdsapi");
extern(Windows)
uint DsWriteAccountSpnW(
    void* hDS,   // HANDLE
    int Operation,   // DS_SPN_WRITE_OP
    const(wchar)* pszAccount,   // LPCWSTR
    uint cSpn,   // DWORD
    wchar** rpszSpn   // LPCWSTR*
);
ccall((:DsWriteAccountSpnW, "NTDSAPI.dll"), stdcall, UInt32,
      (Ptr{Cvoid}, Int32, Cwstring, UInt32, Ptr{Ptr{UInt16}}),
      hDS, Operation, pszAccount, cSpn, rpszSpn)
# hDS : HANDLE -> Ptr{Cvoid}
# Operation : DS_SPN_WRITE_OP -> Int32
# pszAccount : LPCWSTR -> Cwstring
# cSpn : DWORD -> UInt32
# rpszSpn : LPCWSTR* -> Ptr{Ptr{UInt16}}
# stdcall は 32bit のみ意味を持つ(x64 では無視)。
# Unicode(-W): Cwstring には transcode(UInt16, "...") 等で UTF-16 を渡す。
local ffi = require("ffi")
ffi.cdef[[
uint32_t DsWriteAccountSpnW(
    void* hDS,
    int32_t Operation,
    const uint16_t* pszAccount,
    uint32_t cSpn,
    uint16_t** rpszSpn);
]]
local ntdsapi = ffi.load("ntdsapi")
-- ntdsapi.DsWriteAccountSpnW(hDS, Operation, pszAccount, cSpn, rpszSpn)
-- hDS : HANDLE
-- Operation : DS_SPN_WRITE_OP
-- pszAccount : LPCWSTR
-- cSpn : DWORD
-- rpszSpn : LPCWSTR*
-- 構造体/GUIDへのポインタは cdef が通るよう void* で表記(実型は各引数コメント参照)。値渡し構造体・enum は対応する typedef を cdef に追加すること。
-- Unicode(-W): uint16_t* には UTF-16LE のバッファ(ffi.new("uint16_t[?]", ...))を渡す。
const koffi = require('koffi');
const lib = koffi.load('NTDSAPI.dll');
const DsWriteAccountSpnW = lib.func('__stdcall', 'DsWriteAccountSpnW', 'uint32_t', ['void *', 'int32_t', 'str16', 'uint32_t', 'void *']);
// DsWriteAccountSpnW(hDS, Operation, pszAccount, cSpn, rpszSpn)
// hDS : HANDLE -> 'void *'
// Operation : DS_SPN_WRITE_OP -> 'int32_t'
// pszAccount : LPCWSTR -> 'str16'
// cSpn : DWORD -> 'uint32_t'
// rpszSpn : LPCWSTR* -> 'void *'
// 出力ポインタは koffi.out(...) で包む。構造体は koffi.struct で定義。
const lib = Deno.dlopen("NTDSAPI.dll", {
  DsWriteAccountSpnW: { parameters: ["pointer", "i32", "buffer", "u32", "pointer"], result: "u32" },
});
// lib.symbols.DsWriteAccountSpnW(hDS, Operation, pszAccount, cSpn, rpszSpn)
// hDS : HANDLE -> "pointer"
// Operation : DS_SPN_WRITE_OP -> "i32"
// pszAccount : LPCWSTR -> "buffer"
// cSpn : DWORD -> "u32"
// rpszSpn : LPCWSTR* -> "pointer"
// 文字列は "buffer"。Unicode(-W) は new TextEncoder() ではなく UTF-16LE のバイト列(末尾に \x00\x00)を Uint8Array で渡す。
// 値渡し構造体は { struct: [ ...field types... ] } を使用。
<?php
$ffi = FFI::cdef(<<<C
uint32_t DsWriteAccountSpnW(
    void* hDS,
    int32_t Operation,
    const uint16_t* pszAccount,
    uint32_t cSpn,
    uint16_t** rpszSpn);
C, "NTDSAPI.dll");
// $ffi->DsWriteAccountSpnW(hDS, Operation, pszAccount, cSpn, rpszSpn);
// hDS : HANDLE
// Operation : DS_SPN_WRITE_OP
// pszAccount : LPCWSTR
// cSpn : DWORD
// rpszSpn : LPCWSTR*
// 構造体/GUIDへのポインタは cdef が通るよう void* で表記(実型は各引数コメント参照)。値渡し構造体・enum は対応する typedef を cdef に追加すること。
// WINAPI(stdcall): x64 では呼出規約が統一されるため問題なし。x86 では __stdcall 対応のラッパが必要な場合あり。
import com.sun.jna.*;
import com.sun.jna.ptr.*;
import com.sun.jna.win32.StdCallLibrary;
import com.sun.jna.win32.W32APIOptions;

public interface Ntdsapi extends StdCallLibrary {
    Ntdsapi INSTANCE = Native.load("ntdsapi", Ntdsapi.class, W32APIOptions.UNICODE_OPTIONS);
    int DsWriteAccountSpnW(
        Pointer hDS,   // HANDLE
        int Operation,   // DS_SPN_WRITE_OP
        WString pszAccount,   // LPCWSTR
        int cSpn,   // DWORD
        PointerByReference rpszSpn   // LPCWSTR*
    );
}
// Unicode(-W): WString(入力)/char[](出力)で UTF-16 をマーシャリング。
@[Link("ntdsapi")]
lib LibNTDSAPI
  fun DsWriteAccountSpnW = DsWriteAccountSpnW(
    hDS : Void*,   # HANDLE
    Operation : Int32,   # DS_SPN_WRITE_OP
    pszAccount : UInt16*,   # LPCWSTR
    cSpn : UInt32,   # DWORD
    rpszSpn : UInt16**   # LPCWSTR*
  ) : UInt32
end
# 構造体/GUID/enum は lib 内に対応する型定義が必要。
# 呼出規約: x64 は規約統一のため OK。x86(32bit)は WINAPI=stdcall だが Crystal の fun に stdcall 付与構文がなく非対応。
import 'dart:ffi';
import 'package:ffi/ffi.dart';

typedef DsWriteAccountSpnWNative = Uint32 Function(Pointer<Void>, Int32, Pointer<Utf16>, Uint32, Pointer<Pointer<Utf16>>);
typedef DsWriteAccountSpnWDart = int Function(Pointer<Void>, int, Pointer<Utf16>, int, Pointer<Pointer<Utf16>>);
final DsWriteAccountSpnW = DynamicLibrary.open('NTDSAPI.dll')
    .lookupFunction<DsWriteAccountSpnWNative, DsWriteAccountSpnWDart>('DsWriteAccountSpnW');
// hDS : HANDLE -> Pointer<Void>
// Operation : DS_SPN_WRITE_OP -> Int32
// pszAccount : LPCWSTR -> Pointer<Utf16>
// cSpn : DWORD -> Uint32
// rpszSpn : LPCWSTR* -> Pointer<Pointer<Utf16>>
// 文字列は package:ffi の "...".toNativeUtf16()/toNativeUtf8() で変換。
{$mode objfpc}{$H+}
function DsWriteAccountSpnW(
  hDS: THandle;   // HANDLE
  Operation: Integer;   // DS_SPN_WRITE_OP
  pszAccount: PWideChar;   // LPCWSTR
  cSpn: DWORD;   // DWORD
  rpszSpn: PPWideChar   // LPCWSTR*
): DWORD; stdcall;
  external 'NTDSAPI.dll' name 'DsWriteAccountSpnW';
import Foreign
import Foreign.C.Types
import Foreign.C.String

foreign import stdcall safe "DsWriteAccountSpnW"
  c_DsWriteAccountSpnW :: Ptr () -> Int32 -> CWString -> Word32 -> Ptr CWString -> IO Word32
-- hDS : HANDLE -> Ptr ()
-- Operation : DS_SPN_WRITE_OP -> Int32
-- pszAccount : LPCWSTR -> CWString
-- cSpn : DWORD -> Word32
-- rpszSpn : LPCWSTR* -> Ptr CWString
-- 要 GHC(Windows)。stdcall は x64 では ccall として扱われる。ブロックする API は safe 呼び出し推奨。
open Ctypes
open Foreign

let dswriteaccountspnw =
  foreign "DsWriteAccountSpnW"
    ((ptr void) @-> int32_t @-> (ptr uint16_t) @-> uint32_t @-> (ptr (ptr uint16_t)) @-> returning uint32_t)
(* hDS : HANDLE -> (ptr void) *)
(* Operation : DS_SPN_WRITE_OP -> int32_t *)
(* pszAccount : LPCWSTR -> (ptr uint16_t) *)
(* cSpn : DWORD -> uint32_t *)
(* rpszSpn : LPCWSTR* -> (ptr (ptr uint16_t)) *)
(* foreign は cdecl 前提。x64 Windows では WINAPI と一致。構造体は ctypes structure を定義のこと。 *)
(cffi:define-foreign-library ntdsapi (t "NTDSAPI.dll"))
(cffi:use-foreign-library ntdsapi)

(cffi:defcfun ("DsWriteAccountSpnW" ds-write-account-spn-w :convention :stdcall) :uint32
  (h-ds :pointer)   ; HANDLE
  (operation :int32)   ; DS_SPN_WRITE_OP
  (psz-account (:string :encoding :utf-16le))   ; LPCWSTR
  (c-spn :uint32)   ; DWORD
  (rpsz-spn :pointer))   ; LPCWSTR*
; isize/usize(INT_PTR/SIZE_T)は x64 前提で :int64/:uint64。x86 では :int32/:uint32。
use Win32::API;
my $DsWriteAccountSpnW = Win32::API::More->new('NTDSAPI',
    'DWORD DsWriteAccountSpnW(HANDLE hDS, int Operation, LPCWSTR pszAccount, DWORD cSpn, LPVOID rpszSpn)');
# my $ret = $DsWriteAccountSpnW->Call($hDS, $Operation, $pszAccount, $cSpn, $rpszSpn);
# hDS : HANDLE -> HANDLE
# Operation : DS_SPN_WRITE_OP -> int
# pszAccount : LPCWSTR -> LPCWSTR
# cSpn : DWORD -> DWORD
# rpszSpn : LPCWSTR* -> LPVOID
# 値渡し構造体は pack() した文字列、または Win32::API::Struct を使用。
# Unicode(-W): LPCWSTR/LPWSTR は Win32::API が UTF-16 変換を行う。

関連項目

文字セット違い
公式の関連項目
使用する型