Powershell Cryptographic Object without file input - powershell

i do have a variable which contains a base64 string (a certificate).I want to convert this to an cryptoggraphic object via powershell, like this:
$cert_object = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2(".\tmp.txt")
But i´m unable to create this object without this hack because i did not find a way to directly pipe the string to the crypto object...
$cert.value | Out-File -FilePath ".\tmp.txt"
#This parses the base64 and createa a certificate object
$cert_object = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2(".\tmp.txt")
#Remove the uglyness
Remove-Item -Path ".\tmp.txt"
Does anyone now a solution without touching disk?

Assuming $cert.value contains the Base64 string you could convert it from Base64 and use those bytes to target the X509Certificate2(Byte[]) Constructor:
[System.Security.Cryptography.X509Certificates.X509Certificate2]::new(
[Convert]::FromBase64String($cert.value)
)
As an example using a Cert in My:
$bytes = (Get-ChildItem Cert:\CurrentUser\My | Select-Object -First 1).RawData
$cert = [Convert]::ToBase64String($bytes)
[System.Security.Cryptography.X509Certificates.X509Certificate2]::new(
[Convert]::FromBase64String($cert)
)

Related

PFX encoded and back to PFX in Powershell

Is it possible when you convert a PFX to lets say Base64, to then convert it back to PFX ?
$PFX_FILE = get-content 'dummy.pfx' -Encoding Byte
[Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($PFX_FILE)) | Out-File 'dummy.txt'
$BASE64_STR = get-content 'dummy.txt' -Encoding utf8
[Text.Encoding]::Utf8.GetString([Convert]::FromBase64String($BASE64_STR)) | Out-File 'dummy-2.pfx'
The output of line four is unsurprisingly invalid, but I am not sure how to go about it.
I created a PFX cert in location : C:\temp\PowerShellGraphCert.pfx and ran the following. I believe this is what you are looking for.
I converted > PowerShellGraphCert.pfx to PowerShellGraphCert.txt and then back to dummy-3.pfx.
Now PowerShellGraphCert.pfx = dummy-3.pfx
$PFX_FILE = get-content 'C:\temp\PowerShellGraphCert.pfx' -Encoding Byte
$base64 = [System.Convert]::ToBase64String($PFX_FILE) | Out-File 'C:\temp\PowerShellGraphCertbase64.txt'
$BASE64_STR = get-content 'C:\temp\PowerShellGraphCertbase64.txt'
$filename = 'C:\temp\dummy-3.pfx'
$bytes = [Convert]::FromBase64String($BASE64_STR)
[IO.File]::WriteAllBytes($filename, $bytes)

Encode / Decode .EXE into Base64

I have a .NET exe file that I'd like to encode into a Base-64 string, and then at a later point decode into a .exe file from the Base64 string, using Powershell.
What I have so far produces a .exe file, however, the file isn't recognizable to windows as an application that can run, and is always a different length than the file that I'm passing into the encoding script.
I think I may be using the wrong encoding here, but I'm not sure.
Encode script:
Function Get-FileName($initialDirectory)
{
[System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") | Out-Null
$OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog
$OpenFileDialog.initialDirectory = $initialDirectory
$OpenFileDialog.filter = "All files (*.*)| *.*"
$OpenFileDialog.ShowDialog() | Out-Null
$FileName = $OpenFileDialog.filename
$FileName
} #end function Get-FileName
$FileName = Get-FileName
$Data = get-content $FileName
$Bytes = [System.Text.Encoding]::Unicode.GetBytes($Data)
$EncodedData = [Convert]::ToBase64String($Bytes)
Decode Script:
$Data = get-content $FileName
$Bytes = [System.Text.Encoding]::UTF8.GetBytes($Data)
$EncodedData = [System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String($Bytes))
$EncodedData | Out-File ( $FileName )
The problem was caused by:
Get-Content without -raw splits the file into an array of lines thus destroying the code
Text.Encoding interprets the binary code as text thus destroying the code
Out-File is for text data, not binary code
The correct approach is to use IO.File ReadAllBytes:
$base64string = [Convert]::ToBase64String([IO.File]::ReadAllBytes($FileName))
and WriteAllBytes to decode:
[IO.File]::WriteAllBytes($FileName, [Convert]::FromBase64String($base64string))
Just to add an alternative for people looking to do a similar task: Windows comes with certutil.exe (a tool to manipulate certificates) which can base64 encode and decode files.
certutil -encode test.exe test.txt
certutil -decode test.txt test.exe
This is a purely PowerShell version of Swonkie's answer which, despite working quite well if you have access to the utility, isn't a PowerShell answer - which is what I needed.
$SourceFile = "C:\Src\OriginalBinaryFile.dll"
$B64File = "C:\Src\DllAsB64.txt"
$Reconstituted = "C:\Src\ReConstituted.dll"
[IO.File]::WriteAllBytes($B64File,[char[]][Convert]::ToBase64String([IO.File]::ReadAllBytes($SourceFile)))
[IO.File]::WriteAllBytes($Reconstituted, [Convert]::FromBase64String([char[]][IO.File]::ReadAllBytes($B64File)))
As a side note. If the DllAsB64.txt is created by certutil, it will be wrapped by these lines.
-----BEGIN CERTIFICATE-----
-----END CERTIFICATE-----
After removing these lines the PowerShell command above will decode it. Certutil ignores them so it will decode its own output or the PowerShell output.

Powershell not sending the right path for a file as argument

I'm trying to apply a hash function to all the files inside a folder as some kind of version control. The idea is to make a testfile that lists the name of the file and the generated checksum. Digging online I found some code that should do the trick (in theory):
$list = Get-ChildItem 'C:\users\public\documents\folder' -Filter *.cab
$sha1 = New-Object System.Security.Cryptography.SHA1CryptoServiceProvider
foreach ($file in $list) {
$return = "" | Select Name, Hash
$returnname = $file.Name
$returnhash = [System.BitConverter]::ToString($sha1.ComputeHash([System.IO.File]::ReadAllBytes($file.Name)))
$return = "$returnname,$returnhash"
Out-File -FilePath .\mylist.txt -Encoding Default -InputObject ($return) -Append
}
When I run it however, I get an error because it tries to read the files from c:\users\me\, the folder where I'm running the script. And the file c:\users\me\aa.cab does not exist and hence can't be reached.
I've tried everything that I could think of, but no luck. I'm using Windows 7 with Powershell 2.0, if that helps in any way.
Try with .FullName instead of just .Name.
$returnhash = [System.BitConverter]::ToString($sha1.ComputeHash([System.IO.File]::ReadAllBytes($file.FullName)))

Powershell retrieving a variable from a text file

Is there a way to read a text file C:\test.txt and retrieve a particular value?
ie file looks like this:
serverName=serv8496
midasServer=serv8194
I want to set the value of a variable in my script in some way from this file eg:
$MidasServer= (from file midasServer value)
I will not know the line number where the reference is.
Any way to do this?
Yes, read the file, split each line and assign the split result to the Name and Value parameters:
Get-Content file.txt | Foreach-Object{
$var = $_.Split('=')
New-Variable -Name $var[0] -Value $var[1]
}
If that is exactly how your file appears i.e. a list of key value pairs denoted with a equals sign then you should have a look at ConvertFrom-StringData which
converts a string that contains one or more key and value pairs into a hash table. Because each key/value pair must be on a separate line, here-strings are often used as the input format.
So if a text file contained just the data in your example you could do this to create a hashtable
$Path = "C:\temp\test.txt"
$values = Get-Content $Path | Out-String | ConvertFrom-StringData
$values.midasServer
Where the $values.midasServer would have the value serv8194. No need to know where the properties are in respect to the file. Your input file can also have varying leading and trailing space around the equals sign which will give the exact same result.
Depending on your use case you can take that one step farther and create a custom object from that hashtable
New-Object -TypeName pscustomobject -Property $values
If you have at least PowerShell v3 or higher you can simplify the process (assuming you want a custom psobject)
$values = [pscustomobject](Get-Content $Path -Raw | ConvertFrom-StringData)
$values.midasServer
This is an improvement to the Shay Levy's answer. It does the following.
It ignores commented lines and new lines in the file.txt before
start processing the file. So it resolves the error saying that name
could not be created because it is an empty string.
It splits only on the first occurrence of the character "=".
Therefore you can use any characters in the value field.
It performs Trim() operation in order to remove space characters from the beginning and end of the variable/property. Therefore "VARIABLE=VALUE" and "VARIABLE = VALUE" in the file.txt returns the same.
Set the scope of new variables to "Script". Variables created in the
script scope are accessible only within the script file or module
they are created in. Other options are Global, Local and Private.
You can find a variable scope reference here.
Get-Content file.txt | Where-Object {$_.length -gt 0} | Where-Object {!$_.StartsWith("#")} | ForEach-Object {
$var = $_.Split('=',2).Trim()
New-Variable -Scope Script -Name $var[0] -Value $var[1]
}
This was successful for me:
(input file = filename.txt)
[string] $person 'Joe'
[int] $age 50
[datetime] $dob '06/11/1971'
(commands)
Get-Content filename.txt | ForEach-Object {
$invar = $_.Split(" ").Trim()
Invoke-Expression (Invoke-Command -ScriptBlock {
$($invar[0])+$($invar[1])+'='+$($invar[2])
} )
}
If you know there's a "value", that will contain spaces, i.e. "person "Joe B", just join the values, like so...
Replace this:
        $($invar[0])+$($invar[1])+'='+$($invar[2])
With this:
        $($invar[1])+$($invar[2])+'='+ (-join $($invar[3]),$($invar[4]),$($invar[5]) )

Loading a PowerShell hashtable from a file?

I've got a file containing some data in PowerShell Object Notation:
#{ X = 'x'; Y = 'y' }
I'd like to load this into a variable from the file.
(I figured it out while putting together a repro)
PS> $content = ( Get-Content .\foo.pson | Out-String )
PS> $data = ( Invoke-Expression $content )
Get-Content returns an array with the lines in the file; the Out-String is used to join them together.
Invoke-Expression then runs the script, and the result is captured. This is open to injection attacks, but that's OK in my specific case.
Or, if you prefer your PowerShell terse:
PS> $data = gc .\foo.pson | Out-String | iex
(I can't find a shorter form of Out-String)
I've used ConvertFrom-StringData. If you want to use this approach you'll need to change the way you store key/value pairs with each on its own line and no quotes:
#Contents of test.txt
X = x
Y = y
get-content .\test.txt | ConvertFrom-StringData
Name Value
---- -----
X x
Y y
ConvertFrom-StringData is a built-in cmdlet. I created corresponding ConvertTo-StringData function available here http://poshcode.org/1986
I ran into trouble using ConvertFrom-StringData as #Chad suggested. If you do:
$hash = get-content .\test.txt | ConvertFrom-StringData
I found I had an object array rather than a hash table. In fact, it appears that I had an array of hash tables, each with one entry. I confirmed with a:
$hash.GetType()
It looks like you need to join each line of the slurped input file to ensure that it forms a single string for ConvertFrom..'s use:
$hash = ((get-content .\test.txt) -join '`n') | ConvertFrom-StringData
If you can give this file the extension .ps1, say, data.ps1 then it cannot be simpler than this code:
$data = <path>\data.ps1
Starting from PowerShell 5.0 you have
Import-PowerShellDataFile
Which imports values from a .psd1-file. So the only thing you have to do is rename your file to *.psd1
Official help is here.
This is an older post but, this is sort of a twist on your accepted solution and perhaps slightly more "safe", keep in mind un-trusted files.
From your notes, you have a file that contains a hashtable using Powershell syntax. Given that constraint, you can import it directly:
$HashPath = ".\foo.pson"
# input file contents
$filecontent = Get-Content -Path $HashPath -Raw -ErrorAction Stop
# put the file in a script block
$scriptBlock = [scriptblock]::Create( $filecontent )
#check that the file contains no other Powershell commands
$scriptBlock.CheckRestrictedLanguage( $allowedCommands, $allowedVariables, $true )
#execute it to create the hashtable
$hashtable = ( & $scriptBlock )
Note on the $scriptBlock.CheckRestrictedLanguage you could replace that with
$scriptBlock.CheckRestrictedLanguage([string[]]#(), [string[]]#(), $false)
Use an empty list of strings so we do not allow any Powershell commands. When importing a hashtable, this is exactly what we want. That last one is allowEnvironmentVariables so we restrict that in this example with $false.
Side note, a Powershell module (psd1 file) is just a hashtable so this concept may help you to also pull in script blocks or other things.
Reference: https://learn.microsoft.com/en-us/dotnet/api/system.management.automation.scriptblock.checkrestrictedlanguage?view=powershellsdk-1.1.0