Is there a way to embed an exe to an existing powershell script? My boss wants me to come up with a way to install software on our employees computers that work from home and aren't tech savvy. Essentially, I need to copy a file locally to their computer (which is an exe) and run it from within powershell (or command line) terminal with some arguments (i.e., /norestart /quiet, etc).
1 Answer
You can use Base64 encoding to embed an exe in a PowerShell script. Run this script to encode the exe. It produces 'base64Decoder.ps1' in the Downloads folder.
# Requires PowerShell 5.1
# Run this script to encode the exe.
# It produces 'base64Decoder.ps1' in the Downloads folder.
$folder = "$env:UserProfile\Downloads\Demo\"
$file = "PowerShell-7.0.0-win-x64.msi"
$option = [System.Base64FormattingOptions]::InsertLineBreaks
$path = Join-Path -Path $folder -ChildPath $file
$bytes = Get-Content $path -Encoding Byte -ReadCount 0
$outputProgram = [System.Text.StringBuilder]::new()
[void]$outputProgram.AppendLine( '$encodedText = @"' )
[void]$outputProgram.AppendLine( ([Convert]::ToBase64String($bytes, $option)) )
[void]$outputProgram.AppendLine( '"@' )
[void]$outputProgram.Append(
@"
`$downloads = Join-Path -Path `$Env:USERPROFILE -ChildPath "Downloads"
`$file = "$file"
`$path = Join-Path -Path `$downloads -ChildPath `$file
`$value = [System.Convert]::FromBase64String(`$encodedText)
Set-Content -Path `$path -Value `$value -Encoding Byte
"@
)
$downloads = Join-Path -Path $Env:USERPROFILE -ChildPath "Downloads"
$outFile = "base64Decoder.ps1"
$outPath = Join-Path -Path $downloads -ChildPath $outFile
Set-Content -Path $outPath -Value ($outputProgram.ToString())
You can copy and paste the contents of base64Decoder.ps1 into an existing PowerShell script to embed the exe. Or, if too large, include base64Decoder.ps1 with the original script and invoke it when necessary.
Run the script on the target computer to reproduce the original file in the Downloads folder. This is valid PowerShell syntax and can be included in a script.
& "$env:UserProfile\Downloads\base64Decoder.ps1"
You might have to set the execution policy before the script will run.
Set-ExecutionPolicy RemoteSigned
Invoke the exe with Start-Process. This can be saved in a script.
Start-Process -FilePath "$env:UserProfile\Downloads\PowerShell-7.0.0-win-x64.msi" -ArgumentList '/? '
If you want to send a PowerShell script via E-mail, attach it as .txt and have them rename it. I'm sure you know that file attachments are generally limited to 10MB.
If the exe is available online, you can use Invoke-WebRequest which is much easier.
Invoke-WebRequest "https://github.com/PowerShell/PowerShell/releases/download/v7.0.0/PowerShell-7.0.0-win-x64.msi" -outfile "$env:UserProfile\Downloads\PowerShell-7.0.0-win-x64.msi"
You can test these steps in Windows Sandbox.
While this is the technically correct answer to your question, I don't recommend it.
First, it is more complicated than simply downloading an installer from the Internet and using (the MSI) switches on it.
Second, the performance of my script is poor for nontrivial exe's. And it will create more problems than it solves.
I'm not sure what the assumption is here. But if these computers are not managed, I imagine there will be a support request for each install. What you won't be able to do is just E-mail this script to 100 people or put it in a logon script and walk away. That would be very bad. Even if this were in the office, I would not deploy an unattended install without thorough testing. And that's assuming local storage and a logon script or equivalent: not people working from home as a one-off.
Copy-Item -ToSession) and then execute them there (viaInvoke-Command).iexpressfor the inbuilt Windows' installer wizard.