usr/Get-ApiSet.ps1

using namespace System.Runtime.InteropServices

function Get-ApiSet {
  [CmdletBinding()]param()

  begin {
    New-Structure API_SET_NAMESPACE {
      UInt32 Version
      UInt32 Size
      UInt32 Flags
      UInt32 Count
      UInt32 EntryOffset
      UInt32 HashOffset
      UInt32 HashFactor
    }

    New-Structure API_SET_NAMESPACE_ENTRY {
      UInt32 Flags
      UInt32 NameOffset
      UInt32 NameLength
      UInt32 HashedLength
      UInt32 ValueOffset
      UInt32 ValueCount
    }

    New-Structure API_SET_VALUE_ENTRY {
      UInt32 Flags
      UInt32 NameOffset
      UInt32 NameLength
      UInt32 ValueOffset
      UInt32 ValueLength
    }

    New-Delegate ntdll {
      ptr RtlGetCurrentPeb
    }

    $to_i = "ToInt$(($sz = [IntPtr]::Size) * 8)"
  }
  process {}
  end {
    $ptr = [Marshal]::ReadIntPtr([IntPtr]( # ApiSetMap offset
      $ntdll.RtlGetCurrentPeb.Invoke().$to_i() + ($sz -eq 8 ? 0x68 : 0x38)
    ))
    $asn, $mov = ($ptr -as [API_SET_NAMESPACE]), $ptr.$to_i()

    $pasne = [IntPtr]($asn.EntryOffset + $mov) # first entry pointer
    for ($i = 0; $i -lt $asn.Count; $i++) {
      $asne = $pasne -as [API_SET_NAMESPACE_ENTRY]
      $dll = [Marshal]::PtrToStringUni([IntPtr]($asne.NameOffset + $mov), $asne.NameLength / 2)
      $ses = [Boolean]$asne.Flags

      $pasve = [IntPtr]($asne.ValueOffset + $mov)
      $mod = for ($j = 0; $j -lt $asne.ValueCount; $j++) {
        $asve = $pasve -as [API_SET_VALUE_ENTRY]
        [Marshal]::PtrToStringUni([IntPtr]($asve.ValueOffset + $mov), $asve.ValueLength / 2)
        # move to the next value
        $pasve = [IntPtr]($pasve.$to_i() + $asve::GetSize())
      }

      [PSCustomObject]@{
        Module = "$dll.dll"
        Sealed = $ses
        Linked = $mod
      }
      # move to the next entry
      $pasne = [IntPtr]($pasne.$to_i() + $asne::GetSize())
    }
  }
}

Export-ModuleMember -Function Get-ApiSet