function New-AesKey { param ( [ValidateSet(128, 192, 256)] [Int32]$KeySize = 256, [String]$Password, [ValidateScript({ Test-Path -LiteralPath $_ -PathType Leaf })] [String]$PasswordFile, [ValidatePattern('^[0-9A-F]+$')] [String]$Salt, [Int32]$Iter = 10000, [ValidateScript({ Test-Path -LiteralPath $_ -IsValid })] [String]$OutFile, [Switch]$PassThru ) Set-StrictMode -Version Latest $ErrorActionPreference = 'Stop' function ConvertFrom-HexString { param ([Parameter(Mandatory, ValueFromPipeline)][ValidatePattern('^[0-9A-F]+$')][String]$String) end { [Byte[]]($String -replace '..', '0x$&,' -split ',' -ne '') } } function ConvertTo-HexString { param ([Parameter(Mandatory, ValueFromPipeline)][Byte[]]$Bytes) end { ($Bytes | ForEach-Object { $_.ToString('X2') }) -join '' } } function Format-HexString { param ([Parameter(Mandatory, ValueFromPipeline)][ValidatePattern('^[0-9A-F]+$')][String]$String, [Int32]$Bytes = 8) begin { $hexLength = $Bytes * 2 } process { switch ($String) { { $_.Length -lt $hexLength } { $_.PadRight($hexLength, '0') } { $_.Length -gt $hexLength } { $_.Substring(0, $hexLength) } default { $_ } } } } [System.IO.Directory]::SetCurrentDirectory($PWD) if ($Salt) { $saltBytes = $Salt | Format-HexString -Bytes 8 | ConvertFrom-HexString } else { $saltBytes = New-Object Byte[] 8 $prng = New-Object System.Security.Cryptography.RNGCryptoServiceProvider $prng.GetBytes($saltBytes) } if ($PasswordFile) { $PasswordFile = [System.IO.Path]::GetFullPath($PasswordFile) $Password = [System.IO.File]::ReadLines($PasswordFile) } try { $pbkdf2 = New-Object System.Security.Cryptography.Rfc2898DeriveBytes($Password, $saltBytes, $Iter, [System.Security.Cryptography.HashAlgorithmName]::SHA256) } catch { $pbkdf2 = New-Object System.Security.Cryptography.Rfc2898DeriveBytes($Password, $saltBytes, $Iter) } $keyBytes = $pbkdf2.GetBytes($KeySize / 8) $ivBytes = $pbkdf2.GetBytes(16) $result = [Ordered]@{ Salt = ($saltBytes | ConvertTo-HexString) Key = ($keyBytes | ConvertTo-HexString) Iv = ($ivBytes | ConvertTo-HexString) } if ($OutFile) { $OutFile = [System.IO.Path]::GetFullPath($OutFile) if ($PSCmdlet.ShouldProcess($OutFile)) { $lines = $result.Keys | ForEach-Object { '{0,-3}={1}' -f $_.ToLower(), $result[$_] } [System.IO.File]::WriteAllLines($OutFile, $lines) } } if ((-not $OutFile) -or ($OutFile -and $PassThru)) { return $result } } # Example usage: # $AESKey = New-AesKey -KeySize 256 -Password "MySecurePassword" # Write-Host "Generated AES Key: $AESKey"