use strict; use warnings; use Carp qw( croak ); use Win32::API qw( ); use Win32::API::Struct qw( ); use constant DS_IS_DNS_NAME => 0x00020000; typedef Win32::API::Struct GUID => qw { DWORD Data1; WORD Data2; WORD Data3; BYTE Data4[8]; }; sub _link { my $o = Win32::API->new( @_ ); die "Can't link to DsGetDcName in dll Netapi32: $^E\n" if !$o; return $o; } { my $DsGetDcName = _link( 'Netapi32', 'DsGetDcName', 'PPSPNP', 'N' ); my $NetApiBufferFree = _link( 'Netapi32', 'NetApiBufferFree', 'N', 'N' ); my $GUID_FORMAT = 'L S S a8'; my $SIZE_OF_GUID = 4+2+2+ 8; my $DCI_FORMAT = "p p L a$SIZE_OF_GUID p p L p p"; my $SIZE_OF_DCI = 4+4+4+ $SIZE_OF_GUID+4+4+4+4+4; sub DsGetDcName { my $pk_ptr_to_pk_dci = pack('L', 0); if (!(my $rv = $DsGetDcName->Call( @_, $pk_ptr_to_pk_dci ))) { # It uses the same codes as GetLastError $^E = $rv; croak("$^E"); } my $ptr_to_pk_dci = unpack('L', $pk_ptr_to_pk_dci); my $pk_dci = unpack("P$SIZE_OF_DCI", $pk_ptr_to_pk_dci); # If only Win32::API::Struct provided a public # interface that takes a packed struct. my ($dcn, $dca, $dcat, $pk_guid, $dn, $dfn, $flags, $sn, $csn) = unpack($DCI_FORMAT, $pk_dci); my @guid = unpack($GUID_FORMAT, $pk_guid); my $guid = Win32::API::Struct->new('GUID'); @{$guid}{qw( Data1 Data2 Data3 Data4 )} = @guid; if (!(my $rv = $NetApiBufferFree->Call( $ptr_to_pk_dci ))) { # It uses the same codes as GetLastError $^E = $rv; # Don't use carp since it's likely a bug in this sub. warn("Warning: Error from NetApiBufferFree: $^E"); } return { DomainControllerName => $dcn, DomainControllerAddress => $dca, DomainControllerAddressType => $dcat, DomainGuid => \@guid, DomainName => $dn, DnsForestName => $dfn, Flags => $flags, DcSiteName => $sn, ClientSiteName => $csn, }; } } my $domainguid = Win32::API::Struct->new('GUID'); my $dci = DsGetDcName( 'mymachine', 'mydomain', $domainguid, 'myADsite', DS_IS_DNS_NAME, ); use Data::Dumper qw( Dumper ); print Dumper $dci;