How to run a powershell script that is based online - powershell

I have a Powershell script that is stored here:
https://gitlab.example.example.co.uk/example/example/raw/master/shrink-diskpart.ps1
I would like to run this on many servers through a scheduled task from this gitlab so I can make single changes to the script and it will run the most up to date one on all the servers.
Can anyone advise if this is possible an if it is how it can be done?
Thanks

You can use Invoke-WebRequest with -OutFile to download a file, and then just execute it. You might store the file on the web server as a .txt so that you don't have to add a MIME type.
$scriptUrl = "http://localhost/test.txt"
$destination = "c:\temp\test.txt"
$scriptName = "c:\temp\test.ps1"
Invoke-WebRequest $scriptUrl -OutFile $destination
# if the file was downloaded, delete the old script file and rename the new
# file
if(test-path $destination){
remove-item $scriptName
Rename-Item $destination $scriptName
}
&$scriptName
Props to http://www.powershellatoms.com/basic/download-file-website-powershell/

Related

Issue with downloading different file from same website

So I manage to create below script, which will download the .exe file from McAfee website and execute it. However, the name of .exe file in website keeps on changing daily basis. For e.g. file is V3_4756dat.exe, next day version will be changed to V3_4757dat.exe and keeps on incrementing by +1. Any idea what changes I can make in below code to achieve this.
# URL and Destination
$url = "https://download.nai.com/products/datfiles/V3DAT/V3_4756dat.exe"
$dest = "C:\Users\user\Desktop\V3_4756dat.exe"
# Download file
Start-BitsTransfer -Source $url -Destination $dest
#file execution
Start-Process -FilePath “V3_4756dat.exe” -WorkingDirectory “C:\Users\user\Desktop\”
Fortunately, there is access to directory services with belowlocation:
https://download.nai.com/products/datfiles/v3dat/
We can use invoke-webrequest to download the directory content and parse the output file to know the latest name of exe file. After this, you can download the latest file and run the command.
Hope this helps.
With few minor corrections, I can propose below:
# Download the current directory output
$outfile="c:\temp\currentfile.txt"
Invoke-WebRequest "https://download.nai.com/products/datfiles/v3dat/" -OutFile $outfile
$ExeFilename=(gc "c:\temp\abc.log" -tail 3 |where {$_ -match ".exe" }).split("=")[3].split(">")[0].replace("""", "")
Remove-Item $outfile
# URL and Destination
$url = "https://download.nai.com/products/datfiles/v3dat/$ExeFilename"
$dest = "C:\temp\$ExeFilename"
echo $url
# Download file
Start-BitsTransfer -Source $url -Destination "c:\temp\"
#file execution
Start-Process -FilePath "$ExeFilename" -WorkingDirectory "c:\temp\"
Thanks GMaster9 for help in this. I also wanted to run this script on different users, hence using generic folder. Final script turned out to be like this.
#Create a new temp folder
New-Item -Path 'C:\Temp' -ItemType Directory
# Download the current directory output
$outfile="C:\Temp\CurrentDatfiles.txt"
Invoke-WebRequest "https://download.nai.com/products/datfiles/v3dat/" -OutFile $outfile
$ExeFilename=(gc "C:\Temp\CurrentDatfiles.txt" -tail 3 |where {$_ -match ".exe" }).split("=")[3].split(">")[0].replace("""", "")
Remove-Item $outfile
# URL and Destination
$url = "https://download.nai.com/products/datfiles/v3dat/$ExeFilename"
$dest = "C:\Temp\$ExeFilename"
echo $url
# Download file
Start-BitsTransfer -Source $url -Destination "C:\Temp"
#file execution
Start-Process -FilePath "$ExeFilename" -WorkingDirectory "C:\Temp"

PowerShell get directory of a program

I recently wrote a script and want to share it with my colleagues. It’s a simple copy and paste program that creates log-files after each run. The problem is that I used this: start transcript -Path C:\Users…
The program works fine but if anyone else runs the script it won’t be able to create log-files, since the directory is a copy of mine.
Now to my question: Is there anyway that the program can find out the directory where each user saved the script so it can create a sub-folder in that directory and then dump the logs in there?
Thank you in advance
The path to the folder containing the currently executing script can be obtained through the $PSScriptRoot automatic variable:
Start-Transcript -OutputDirectory $PSScriptRoot
Here's how I record PowerShell sessions using the Start-Transcript cmdlet. It creates a log file, where the script is run from.
#Log File Paths
$Path = Get-Location
$Path = $Path.ToString()
$Date = Get-Date -Format "yyyy-MM-dd-hh-mm-ss"
$Post = "\" + (Get-Date -Format "yyyy-MM-dd-hh-mm-ss") + "-test.log"
$PostLog = $Path + $Post
$PostLog = $PostLog.ToString()
#Start Transcript
Start-Transcript -Path $PostLog -NoClobber -IncludeInvocationHeader
#Your Script
Get-Date
#End Transcript
Stop-Transcript -ErrorAction Ignore

Powershell script with embedded exe

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).
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.

Install an .MSI file from the same directory as the powershell script without setting a static file path

I have a script that we use that is in Powershell however I need the script to be able to find the files that it needs to install an application dynamically as users can copy the folder to any folder on their computer. Currently I have the below code set, I guess my question is, if the script is in the same folder as the install files. How do I tell powershell to just look in the directory that its being ran from for the install files?
$Install = "C:\Other Folder\File.msi"
$InstallArg = "/quite /norestart"
Start-Process '
-FilePath $Install '
-ArgumentList $InstallArg '
-PassThru | Wait-Process
Any help would be appreciated. Thank you.
Update, I found that I have to be in the directory the script is in. However since we have to run ISE with admin credentials it automatically defaults to C:\Windows\System32 as the directory powershell is looking in regardless if I tell it to open the script. If that is the case how can I tell it to look where the script is located so that it can find the files that it needs?
I have found my answer below is how I got it to work with our current situation. Thank you Thomas for the help!
$ScriptLocation = Get-ChildItem -Path C:\Users -Filter Untitled2.ps1 -Recurse | Select Directory
cd $ScriptLocation.Directory
$Install = ".\Install.msi"
$InstallArg = "/quite /norestart"
Start-Process '
-FilePath $Install '
-ArgumentList $InstallArg '
-PassThru | Wait-Process
Define a relative path:
$Install = ".\File.msi"
If you are not running the script inside the directory, where the script itself and the executable are stored, you will have to determine the absolute path to it. With PowerShell 3+ you can easily determine the directory, where your script is stored, using the $PSScriptRoot variable. You could define your $Install variable like this:
$Install = Join-Path -Path $PSScriptRoot -ChildPath "File.msi"
Thank you so much for your help everyone! I accidentally stumbled upon the perfect solution.
# Set active path to script-location:
$path = $MyInvocation.MyCommand.Path
if (!$path) {
$path = $psISE.CurrentFile.Fullpath
}
if ($path) {
$path = Split-Path $path -Parent
}
Set-Location $path

Adding If / If Not statement into PowerShell

We are moving to JumpCloud AD services, and with that, comes automated deployment commands from the JumpCloud console. I've created a script that works with Chocolatey to install some apps, and the ones not on Chocolatey I have them in an S3 bucket on AWS that I've tied into a Invoke-WebRequest -Uri command to pull the package, and copy it to the destination folder.
The problem I'm running into, is, I want the command to run, but I want it to check and see if the install files are already there, if they are, move onto the next item, if they aren't, then copy the file over.
Anyone willing to give me a few pointers? Currently have 7 packages being copied over, so I assume I'll need 7 if statements.
Here is the code of what I have attempted so far:
if ( -not (Test-Path -path "C:\Windows\Temp\JC_ScheduledTasks")) {
New-Item -Path "C:\Windows\Temp\JC_ScheduledTasks" -ItemType directory
}
But I'm not sure how to tweak that for items pulled from AWS:
Invoke-WebRequest -Uri "cavo-deploy-virginia.s3.amazonaws.com/QualysCloudAgent.exe" -OutFile "c:\jumpcloud\QualysCloudAgent.exe"
Since you have an array of files that you want to do the same set of commands for. Then use simple loop either using foreach or ForEach-Object.
$DestinationFolder = 'c:\jumpcloud\' #'
# Define the array here or use Get-Content for a list from a text file
$Files = #('QualysCloudAgent.exe','example1.exe')
foreach ($File in $Files) {
# Determine the destination for the file
$DestinationFile = Join-Path $DestinationFolder $File
# Validate if the file already exists
if ( -not (Test-Path $DestinationFile)) {
Invoke-WebRequest -Uri "cavo-deploy-virginia.s3.amazonaws.com/$File" -OutFile $DestinationFile
}
}