Public/Get-NTLMHash.ps1

function Get-NTLMHash {
    [CmdletBinding()]
    [OutputType([string],[byte[]])]
    param (
        [Parameter(Mandatory,Position=0,ValueFromPipeline)]
        [ValidateScript({Test-ValidPassObject $_ -ThrowOnFail})]
        [object]$InputObject,
        [switch]$AsBytes
    )

    # Adapted From:
    # https://github.com/LarrysGIT/MD4-powershell
    # https://tools.ietf.org/html/rfc1320
    #
    # Example:
    # Get-NTLMHash 'hello' # 066DDFD4EF0E9CD7C256FE77191EF43C
    # 'password' | Get-NTLMHash # 8846F7EAEE8FB117AD06BDD830B7586C

    Begin {

        # Basic MD4 functions (F, G, H)
        function fF([uint32]$X, [uint32]$Y, [uint32]$Z)
        {
            (($X -band $Y) -bor ((-bnot $X) -band $Z))
        }
        function fG ([uint32]$X, [uint32]$Y, [uint32]$Z)
        {
            (($X -band $Y) -bor ($X -band $Z) -bor ($Y -band $Z))
        }
        function fH ([uint32]$X, [uint32]$Y, [uint32]$Z)
        {
            ($X -bxor $Y -bxor $Z)
        }

        # Rotate Bits Left
        function ROL ([UInt32]$val, [Int32]$bits)
        {
            ($val -shl $bits) -bor ($val -shr (32 - $bits))
        }

        $R2Val = 0x5A827999
        $R3Val = 0x6ED9EBA1

    }

    Process {

        if ($InputObject -is [string]) {
            $BytesToHash = [Text.Encoding]::Unicode.GetBytes($InputObject)
        }
        elseif ($InputObject -is [securestring]) {
            # TODO: Investigate if there are more secure ways to go directly from a SecureString to byte array
            $secPlain = (New-Object PSCredential "user",$InputObject).GetNetworkCredential().Password
            $BytesToHash = [Text.Encoding]::Unicode.GetBytes($secPlain)
        }
        elseif ($InputObject -is [pscredential]) {
            $secPlain = $InputObject.GetNetworkCredential().Password
            $BytesToHash = [Text.Encoding]::Unicode.GetBytes($secPlain)
        }

        # padding 100000*** to length 448, last (64 bits / 8) 8 bytes fill with original length
        # at least one (512 bits / 8) 64 bytes array
        $M = New-Object Byte[] (([math]::Floor($BytesToHash.Count/64) + 1) * 64)
        # copy original byte array, start from index 0
        $BytesToHash.CopyTo($M, 0)
        # padding bits 1000 0000
        $M[$BytesToHash.Count] = 0x80
        # padding bits 0000 0000 to fill length (448 bits /8) 56 bytes
        # Default value is 0 when creating a new byte array, so, no action
        # padding message length to the last 64 bits
        @([BitConverter]::GetBytes($BytesToHash.Count * 8)).CopyTo($M, $M.Count - 8)

        # message digest buffer (A,B,C,D)
        $A = [UInt32]'0x67452301'
        $B = [UInt32]'0xefcdab89'
        $C = [UInt32]'0x98badcfe'
        $D = [UInt32]'0x10325476'

        # processing message in one-word blocks
        for($i = 0; $i -lt $M.Count; $i += 64)
        {
            # Save a copy of A/B/C/D
            $AA = $A
            $BB = $B
            $CC = $C
            $DD = $D

            # Round 1
            $A = (ROL (($A + (fF $B $C $D) + [BitConverter]::ToUInt32($M, ($i + 0))) -band [UInt32]::MaxValue) 3)
            $D = (ROL (($D + (fF $A $B $C) + [BitConverter]::ToUInt32($M, ($i + 4))) -band [UInt32]::MaxValue) 7)
            $C = (ROL (($C + (fF $D $A $B) + [BitConverter]::ToUInt32($M, ($i + 8))) -band [UInt32]::MaxValue) 11)
            $B = (ROL (($B + (fF $C $D $A) + [BitConverter]::ToUInt32($M, ($i + 12))) -band [UInt32]::MaxValue) 19)

            $A = (ROL (($A + (fF $B $C $D) + [BitConverter]::ToUInt32($M, ($i + 16))) -band [UInt32]::MaxValue) 3)
            $D = (ROL (($D + (fF $A $B $C) + [BitConverter]::ToUInt32($M, ($i + 20))) -band [UInt32]::MaxValue) 7)
            $C = (ROL (($C + (fF $D $A $B) + [BitConverter]::ToUInt32($M, ($i + 24))) -band [UInt32]::MaxValue) 11)
            $B = (ROL (($B + (fF $C $D $A) + [BitConverter]::ToUInt32($M, ($i + 28))) -band [UInt32]::MaxValue) 19)

            $A = (ROL (($A + (fF $B $C $D) + [BitConverter]::ToUInt32($M, ($i + 32))) -band [UInt32]::MaxValue) 3)
            $D = (ROL (($D + (fF $A $B $C) + [BitConverter]::ToUInt32($M, ($i + 36))) -band [UInt32]::MaxValue) 7)
            $C = (ROL (($C + (fF $D $A $B) + [BitConverter]::ToUInt32($M, ($i + 40))) -band [UInt32]::MaxValue) 11)
            $B = (ROL (($B + (fF $C $D $A) + [BitConverter]::ToUInt32($M, ($i + 44))) -band [UInt32]::MaxValue) 19)

            $A = (ROL (($A + (fF $B $C $D) + [BitConverter]::ToUInt32($M, ($i + 48))) -band [UInt32]::MaxValue) 3)
            $D = (ROL (($D + (fF $A $B $C) + [BitConverter]::ToUInt32($M, ($i + 52))) -band [UInt32]::MaxValue) 7)
            $C = (ROL (($C + (fF $D $A $B) + [BitConverter]::ToUInt32($M, ($i + 56))) -band [UInt32]::MaxValue) 11)
            $B = (ROL (($B + (fF $C $D $A) + [BitConverter]::ToUInt32($M, ($i + 60))) -band [UInt32]::MaxValue) 19)

            # Round 2
            $A = (ROL (($A + (fG $B $C $D) + [BitConverter]::ToUInt32($M, ($i + 0)) + $R2Val) -band [UInt32]::MaxValue) 3)
            $D = (ROL (($D + (fG $A $B $C) + [BitConverter]::ToUInt32($M, ($i + 16)) + $R2Val) -band [UInt32]::MaxValue) 5)
            $C = (ROL (($C + (fG $D $A $B) + [BitConverter]::ToUInt32($M, ($i + 32)) + $R2Val) -band [UInt32]::MaxValue) 9)
            $B = (ROL (($B + (fG $C $D $A) + [BitConverter]::ToUInt32($M, ($i + 48)) + $R2Val) -band [UInt32]::MaxValue) 13)

            $A = (ROL (($A + (fG $B $C $D) + [BitConverter]::ToUInt32($M, ($i + 4)) + $R2Val) -band [UInt32]::MaxValue) 3)
            $D = (ROL (($D + (fG $A $B $C) + [BitConverter]::ToUInt32($M, ($i + 20)) + $R2Val) -band [UInt32]::MaxValue) 5)
            $C = (ROL (($C + (fG $D $A $B) + [BitConverter]::ToUInt32($M, ($i + 36)) + $R2Val) -band [UInt32]::MaxValue) 9)
            $B = (ROL (($B + (fG $C $D $A) + [BitConverter]::ToUInt32($M, ($i + 52)) + $R2Val) -band [UInt32]::MaxValue) 13)

            $A = (ROL (($A + (fG $B $C $D) + [BitConverter]::ToUInt32($M, ($i + 8)) + $R2Val) -band [UInt32]::MaxValue) 3)
            $D = (ROL (($D + (fG $A $B $C) + [BitConverter]::ToUInt32($M, ($i + 24)) + $R2Val) -band [UInt32]::MaxValue) 5)
            $C = (ROL (($C + (fG $D $A $B) + [BitConverter]::ToUInt32($M, ($i + 40)) + $R2Val) -band [UInt32]::MaxValue) 9)
            $B = (ROL (($B + (fG $C $D $A) + [BitConverter]::ToUInt32($M, ($i + 56)) + $R2Val) -band [UInt32]::MaxValue) 13)

            $A = (ROL (($A + (fG $B $C $D) + [BitConverter]::ToUInt32($M, ($i + 12)) + $R2Val) -band [UInt32]::MaxValue) 3)
            $D = (ROL (($D + (fG $A $B $C) + [BitConverter]::ToUInt32($M, ($i + 28)) + $R2Val) -band [UInt32]::MaxValue) 5)
            $C = (ROL (($C + (fG $D $A $B) + [BitConverter]::ToUInt32($M, ($i + 44)) + $R2Val) -band [UInt32]::MaxValue) 9)
            $B = (ROL (($B + (fG $C $D $A) + [BitConverter]::ToUInt32($M, ($i + 60)) + $R2Val) -band [UInt32]::MaxValue) 13)

            # Round 3
            $A = (ROL (($A + (fH $B $C $D) + [BitConverter]::ToUInt32($M, ($i + 0)) + $R3Val) -band [UInt32]::MaxValue) 3)
            $D = (ROL (($D + (fH $A $B $C) + [BitConverter]::ToUInt32($M, ($i + 32)) + $R3Val) -band [UInt32]::MaxValue) 9)
            $C = (ROL (($C + (fH $D $A $B) + [BitConverter]::ToUInt32($M, ($i + 16)) + $R3Val) -band [UInt32]::MaxValue) 11)
            $B = (ROL (($B + (fH $C $D $A) + [BitConverter]::ToUInt32($M, ($i + 48)) + $R3Val) -band [UInt32]::MaxValue) 15)

            $A = (ROL (($A + (fH $B $C $D) + [BitConverter]::ToUInt32($M, ($i + 8)) + $R3Val) -band [UInt32]::MaxValue) 3)
            $D = (ROL (($D + (fH $A $B $C) + [BitConverter]::ToUInt32($M, ($i + 40)) + $R3Val) -band [UInt32]::MaxValue) 9)
            $C = (ROL (($C + (fH $D $A $B) + [BitConverter]::ToUInt32($M, ($i + 24)) + $R3Val) -band [UInt32]::MaxValue) 11)
            $B = (ROL (($B + (fH $C $D $A) + [BitConverter]::ToUInt32($M, ($i + 56)) + $R3Val) -band [UInt32]::MaxValue) 15)

            $A = (ROL (($A + (fH $B $C $D) + [BitConverter]::ToUInt32($M, ($i + 4)) + $R3Val) -band [UInt32]::MaxValue) 3)
            $D = (ROL (($D + (fH $A $B $C) + [BitConverter]::ToUInt32($M, ($i + 36)) + $R3Val) -band [UInt32]::MaxValue) 9)
            $C = (ROL (($C + (fH $D $A $B) + [BitConverter]::ToUInt32($M, ($i + 20)) + $R3Val) -band [UInt32]::MaxValue) 11)
            $B = (ROL (($B + (fH $C $D $A) + [BitConverter]::ToUInt32($M, ($i + 52)) + $R3Val) -band [UInt32]::MaxValue) 15)

            $A = (ROL (($A + (fH $B $C $D) + [BitConverter]::ToUInt32($M, ($i + 12)) + $R3Val) -band [UInt32]::MaxValue) 3)
            $D = (ROL (($D + (fH $A $B $C) + [BitConverter]::ToUInt32($M, ($i + 44)) + $R3Val) -band [UInt32]::MaxValue) 9)
            $C = (ROL (($C + (fH $D $A $B) + [BitConverter]::ToUInt32($M, ($i + 28)) + $R3Val) -band [UInt32]::MaxValue) 11)
            $B = (ROL (($B + (fH $C $D $A) + [BitConverter]::ToUInt32($M, ($i + 60)) + $R3Val) -band [UInt32]::MaxValue) 15)

            # Increment
            $A = ($A + $AA) -band [UInt32]::MaxValue
            $B = ($B + $BB) -band [UInt32]::MaxValue
            $C = ($C + $CC) -band [UInt32]::MaxValue
            $D = ($D + $DD) -band [UInt32]::MaxValue

        }

        # Output
        $A = ('{0:x8}' -f $A) -ireplace '^(\w{2})(\w{2})(\w{2})(\w{2})$', '$4$3$2$1'
        $B = ('{0:x8}' -f $B) -ireplace '^(\w{2})(\w{2})(\w{2})(\w{2})$', '$4$3$2$1'
        $C = ('{0:x8}' -f $C) -ireplace '^(\w{2})(\w{2})(\w{2})(\w{2})$', '$4$3$2$1'
        $D = ('{0:x8}' -f $D) -ireplace '^(\w{2})(\w{2})(\w{2})(\w{2})$', '$4$3$2$1'

        if ($AsBytes) {
            return (Convert-HexToByteArray "$A$B$C$D")
        } else {
            return "$A$B$C$D".ToUpper()
        }

    }

    <#
    .SYNOPSIS
        Returns an NTLM hash for the specified String, SecureString, or PSCredential password.
 
    .DESCRIPTION
        NTLM hashes are generally used with Windows and are basically just an MD4 hash of a string encoded as UTF16 Little Endian.
 
        This function will accept a standard String, SecureString, or PSCredential as input.
 
    .PARAMETER InputObject
        A String, SecureString, or PSCredential object to hash. The username on a PSCredential object is ignored.
 
    .PARAMETER AsBytes
        If specified, the hash will be returned as a byte array instead of a string.
 
    .EXAMPLE
        Get-NTLMHash 'password'
 
        Get the NTLM hash for 'password'.
 
    .EXAMPLE
        $secString = Read-Host -Prompt 'Secret' -AsSecureSTring
        PS C:\>Get-NTLMHash $secString
 
        Get the NTLM hash for the specified SecureString.
 
    .EXAMPLE
        $cred = Get-Credential
        PS C:\>Get-NTLMHash $cred
 
        Get the NTLM hash for the specified credential.
 
    .EXAMPLE
        $hashBytes = Get-NTLMHash 'password' -AsBytes
 
        Get the NTLM hash as a byte array for 'password'.
 
    .LINK
        Get-SHA1Hash
 
    #>

}