banshee is under active development: collectors will keep changing, and a version you publish will likely need adjustments. For stable use, wait for version 1.0.0.

Active Directory

banshee/active-directory-collection/active-directory/winrm/

fsmo

The holder of each of the five FSMO roles and whether it answers on the LDAP port, by WinRM and PowerShell

  • active-directory
  • domain-controller
  • fsmo
  • winrm
  • powershell

by banshee1 installation2 versions

Keen 1.0.0 · 56 lines
// The five FSMO roles of the forest and of the domain of a domain controller, by WinRM: the domain controller
// that holds each one, as this domain controller knows it, and whether that holder accepts a connection on
// the LDAP port, 389, from this domain controller.
// Runs one PowerShell script that only reads, through the classes of .NET that Microsoft documents:
// DomainController.GetDomainController, then Forest.SchemaRoleOwner and NamingRoleOwner, Domain.PdcRoleOwner,
// RidRoleOwner and InfrastructureRoleOwner. A holder is reached by a TCP connection that sends nothing, given
// up after 3 seconds: a bind with the account would also depend on whether the remote session can hand its
// credentials on to another server, which a WinRM session authenticated by NTLM cannot.
// The script is the one of active-directory/ssh/fsmo, without the powershell -Command "..." that cmd.exe
// needs there.
need('protocol:winrm');

per('role', 'Roles');
output('holder', 'text', array('label' => 'Holder', 'per' => 'role'));
output('reachable', 'text', array('label' => 'Reachable', 'per' => 'role'));

watch.state('unreachable', 'Role holder unreachable', 'reachable', array('critical' => array('no')));

$read = winrm.run("$ErrorActionPreference = 'Stop'; "
    . "[Console]::OutputEncoding = New-Object System.Text.UTF8Encoding; "
    . "$computer = Get-CimInstance Win32_ComputerSystem; "
    . "$server = $computer.DNSHostName + '.' + $computer.Domain; "
    . "$context = New-Object DirectoryServices.ActiveDirectory.DirectoryContext('DirectoryServer', $server); "
    . "$dc = [DirectoryServices.ActiveDirectory.DomainController]::GetDomainController($context); "
    . "$holders = [ordered]@{"
    . "schema = $dc.Forest.SchemaRoleOwner.Name; "
    . "'domain-naming' = $dc.Forest.NamingRoleOwner.Name; "
    . "pdc = $dc.Domain.PdcRoleOwner.Name; "
    . "rid = $dc.Domain.RidRoleOwner.Name; "
    . "infrastructure = $dc.Domain.InfrastructureRoleOwner.Name}; "
    . "$roles = @(foreach ($role in $holders.Keys) {"
    . " $reachable = $false;"
    . " try { $tcp = New-Object Net.Sockets.TcpClient;"
    . " $reachable = $tcp.BeginConnect($holders[$role], 389, $null, $null).AsyncWaitHandle.WaitOne(3000) -and $tcp.Connected;"
    . " $tcp.Close() } catch { };"
    . " @{role = $role; holder = $holders[$role]; reachable = $reachable} }); "
    . "ConvertTo-Json -Compress -Depth 4 -InputObject @{roles = $roles}");
$answer = text.trim($read['output']);
if (list.count(text.match($answer, '^\{')) == 0) {
    fail('misconfigured', 'PowerShell did not return the FSMO roles', $answer . $read['errors']);
}
$fsmo = json.read($answer);

$roles = 0;
foreach ($fsmo['roles'] as $role) {
    $roles = $roles + 1;
    value('holder', $role['holder'], $role['role']);
    if ($role['reachable']) {
        value('reachable', 'yes', $role['role']);
    } else {
        value('reachable', 'no', $role['role']);
    }
}
if ($roles != 5) {
    fail('misconfigured', 'PowerShell did not return the five FSMO roles', $answer);
}