Self building powershell script - powershell

I'm currently trying to make ps1 script that creates another ps1 script via echo, add-content, clip and so forth.
What I'm trying to do is write a ps1 script that gets a folder, stores it in a variable ($VBS) and writes the new ps1 to a file in that folder to afterwards run it from that folder. Here's my code so far:
if (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) { Start-Process powershell.exe -windowstyle hidden "-NoProfile -ExecutionPolicy RemoteSigned -File `"$PSCommandPath`"" -Verb RunAs; exit }
cd \
$VBS = gci -Recurse -Filter "Folder" -Directory -ErrorAction SilentlyContinue -path "C:\"
cd "$env:USERPROFILE\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup"
echo $VBS | ForEach-Object { $_.FullName } > KickStart.ps1
cat KickStart.ps1 | set-clipboard
echo '"if (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) { Start-Process powershell.exe -windowstyle hidden "-NoProfile -ExecutionPolicy RemoteSigned -File `"$PSCommandPath`"" -Verb RunAs; exit }' > KickStart.ps1
add-content KickStart.ps1 "`ncd \"
add-content KickStart.ps1 "`ncd"
add-content KickStart.ps1 ' "'
add-content KickStart.ps1 | get-clipboard
add-content KickStart.ps1 '"'
add-content KickStart.ps1 '`nstart File.vbs'
add-content KickStart.ps1 '`n cd \'
add-content KickStart.ps1 '`ncd "$env:USERPROFILE\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup"'
add-content KickStart.ps1 'rm KickStart.ps1'
The final product (KickStart.ps1) should look like this:
if (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) { Start-Process powershell.exe -windowstyle hidden "-NoProfile -ExecutionPolicy RemoteSigned -File `"$PSCommandPath`"" -Verb RunAs; exit }
cd \
cd "C:\PATH\TO\FOLDER"
start file.vbs
cd \
cd "$env:USERPROFILE\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup"
rm KickStart.ps1
Instead my current scripts generates this:
"if (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) { Start-Process powershell.exe -windowstyle hidden "-NoProfile -ExecutionPolicy RemoteSigned -File `"$PSCommandPath`"" -Verb RunAs; exit }
cd \
cd
"
"
`nstart File.vbs
`n cd \
`ncd "$env:USERPROFILE\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup"
rm KickStart.ps1
I seriously don't know what I'm doing wrong, I've put in almost 12 hours finding the solutions, help would be appreciated.

Although not entirely sure what you are trying to achieve, but looking at the desired output, why not build the content using a Here-String like this:
#'
if (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]"Administrator")) {
Start-Process powershell.exe -WindowStyle Hidden -NoProfile -ExecutionPolicy RemoteSigned -File "$PSCommandPath" -Verb RunAs
exit
}
Set-Location \
Set-Location "C:\PATH\TO\FOLDER"
Start-Process file.vbs
Set-Location \
Set-Location "$env:USERPROFILE\AppData\Roaming\Microsoft\Windows\Start-Process Menu\Programs\Startup"
Remove-Item KickStart.ps1
'# | Set-Content -Path 'THE PATH FOR THE KickStart.ps1 FILE'
Result:
if (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]"Administrator")) {
Start-Process powershell.exe -WindowStyle Hidden -NoProfile -ExecutionPolicy RemoteSigned -File "$PSCommandPath" -Verb RunAs
exit
}
Set-Location \
Set-Location "C:\PATH\TO\FOLDER"
Start-Process file.vbs
Set-Location \
Set-Location "$env:USERPROFILE\AppData\Roaming\Microsoft\Windows\Start-Process Menu\Programs\Startup"
Remove-Item KickStart.ps1

Related

How to add -OutputPath parameter to Powershell script being called from batch file?

Using a batch file to call a Powershell script (this part is working and saving the output files locally):
PowerShell.exe -NoProfile -Command "& {Start-Process PowerShell.exe -ArgumentList '-NoProfile -ExecutionPolicy Bypass -WindowStyle Hidden -File ""%~dpn0.ps1 -Update""' -Verb RunAs}"
Trying to add in a parameter to redirect the output of the script to a folder (per the code comments it can be to a local or UNC path):
-OutputPath Z:\Current
Have tried inserting it everywhere I can think of in the script, cannot get it to work; am thinking it should go in like this(?):
PowerShell.exe -NoProfile -Command "& {Start-Process PowerShell.exe -ArgumentList '-NoProfile -ExecutionPolicy Bypass -WindowStyle Hidden -File ""%~dpn0.ps1 -OutputPath Z:\Current""' -Verb RunAs}"
Here is where the output path is determined in the code:
# If -OutputPath not specified, set default
If (-not($OutputPath)) {
Switch ($OSPlatform) {
"Windows" {
$OutputPath = "$env:PUBLIC\Documents\ Compliance"
if (!(Test-Path $OutputPath)) {
$null = New-Item -Path $(Split-Path -Path $OutputPath -Parent) -Name $(Split-Path -Path $OutputPath -Leaf) -ItemType Directory
}
}
"Linux" {
$OutputPath = "/opt/STIG_Compliance"
if (!(Test-Path $OutputPath)) {
sudo mkdir $OutputPath
}
}
}
}
From what I can find online, the -OutputPath Z:\Current should come immediately after the .ps1 command, but not sure where it should be inserted amongst the other options being used in the batch file.
The script is not throwing off any errors, but is running and saving the output in the default locatin. I am not that well-versed in Powershell; am I missing something?
Thanks in advance for your help!!
It seems like you're trying to pass the OutputPath parameter to your PowerShell script through the command line argument -File. I believe the correct way to pass parameters to a PowerShell script is to include them in the argument list of the PowerShell command.
You could update your command to include the OutputPath parameter in the argument list, like this:
PowerShell.exe -NoProfile -Command "& {Start-Process PowerShell.exe -ArgumentList '-NoProfile -ExecutionPolicy Bypass -WindowStyle Hidden -File ""%~dpn0.ps1""', '-OutputPath', 'Z:\Current' -Verb RunAs}"
Also, make sure to update your PowerShell script to properly use the OutputPath parameter, like this:
# If -OutputPath not specified, set default
if (-not $OutputPath) {
switch ($OSPlatform) {
"Windows" {
$OutputPath = "$env:PUBLIC\Documents\Compliance"
if (!(Test-Path $OutputPath)) {
$null = New-Item -Path $(Split-Path -Path $OutputPath -Parent) -Name $(Split-Path -Path $OutputPath -Leaf) -ItemType Directory
}
}
"Linux" {
$OutputPath = "/opt/STIG_Compliance"
if (!(Test-Path $OutputPath)) {
sudo mkdir $OutputPath
}
}
}
}
# Redirect output to the specified output path
if ($OutputPath) {
$OutputFile = Join-Path -Path $OutputPath -ChildPath "output.txt"
Write-Output "Writing output to $OutputFile"
# Your code to generate output here
# ...
Out-File -FilePath $OutputFile -InputObject "Output data"
}
else {
# Your code to generate output here
# ...
}
Hopefully this helps ya.

Install Chrome on Windows with a .bat file using PowerShell

I was searching around and found a few hints but a few detail pieces are missing.
Here is what I have:
install-chrome.bat
PowerShell -NoProfile -Command "&{Start-Process PowerShell -ArgumentList '-NoProfile -File install-chrome.ps1' -Verb RunAs}"
install-chrome.ps1
$client = New-Object System.Net.WebClient;
$client.DownloadFile("https://dl.google.com/chrome/install/ChromeStandaloneSetup64.exe", ".\ChromeStandaloneSetup64.exe");
.\ChromeStandaloneSetup64.exe /silent /install ;
Two things are not working as expected:
I still get a UAC popup even though the posts I found state that the above should start PowerShell in Admin mode.
I was expecting .\ would download the .exe to the directory the .ps1 and .bat scripts are located.
Any hints on how to solve this?
EDIT:
Thanks to the reply from #TheIncorrigible1 I managed to solve the second part. Both options work more or less (it downloads it, but the installation throws an error locally) when I execute them directly in PowerShell:
< V3
$PSScriptRoot = Split-Path -Parent -Path $script:MyInvocation.MyCommand.Path
$uri = "https://dl.google.com/chrome/install/ChromeStandaloneSetup64.exe"
$path = "$PSScriptRoot\ChromeStandaloneSetup64.exe"
$client = New-Object System.Net.WebClient
$client.DownloadFile($uri, $path)
& $path /install
V3+
$uri = "https://dl.google.com/chrome/install/ChromeStandaloneSetup64.exe"
$path = "$PSScriptRoot\ChromeStandaloneSetup64.exe"
Invoke-WebRequest -Uri $uri -OutFile $path
& $path /install
But the batch still throws errors:
At line:1 char:62
+ ... tart-Process PowerShell -Verb RunAs -ArgumentList -NoProfile, -File, ...
+ ~
Missing argument in parameter list.
At line:1 char:69
+ ... ocess PowerShell -Verb RunAs -ArgumentList -NoProfile, -File, 'C:\Pro ...
+ ~
Missing argument in parameter list.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : MissingArgument
Two things-
You don't need to wrap your batch command to powershell in a scriptblock and -ArgumentList expects an array of string arguments:
powershell.exe -NoProfile -Command "Start-Process -FilePath powershell.exe -ArgumentList #('-NoProfile', '-File', '%~dp0install-chrome.ps1') -Verb RunAs"
There's an automatic variable, $PSScriptRoot, to determine where your root directory is:
$uri = 'https://dl.google.com/chrome/install/ChromeStandaloneSetup64.exe'
if (-not $PSScriptRoot) {
$PSScriptRoot = Split-Path -Parent -Path $script:MyInvocation.MyCommand.Definition
}
$outFile = "$PSScriptRoot\ChromeStandaloneSetup64.exe"
if ($PSVersionTable.PSVersion.Major -lt 3) {
(New-Object -TypeName System.Net.WebClient).DownloadFile($uri, $outFile)
}
else {
Invoke-WebRequest -Uri $uri -OutFile $outFile
}
& $outFile /silent /install
Here you go:
$Path = $env:TEMP; $Installer = "chrome_installer.exe"; Invoke-WebRequest "http://dl.google.com/chrome/install/375.126/chrome_installer.exe" -OutFile $Path\$Installer; Start-Process -FilePath $Path\$Installer -Args "/silent /install" -Verb RunAs -Wait; Remove-Item $Path\$Installer

"Open Admin Powershell here" Windows Explorer Context Menu

I wanted to add an item to the windows explorer context menu, that would open a PowerShell as Admin.
I found this command which starts the powershell in the cmd:
PowerShell -windowstyle hidden -Command `"Start-Process cmd -ArgumentList '/s,/k,pushd,%V && PowerShell' -Verb RunAs`"
The problem with this is that the window is the cmd window and not the powershell one.
So I tried to make a command on my own and came up with this:
PowerShell.exe -WindowStyle Hidden -NoExit -Command "Start-Process PowerShell.exe -Verb RunAs -ArgumentList #(`'-NoExit`',`'-Command`',`'Set-Location -LiteralPath `"%V`"`')";
which works fine when executed in the cmd or powershell, but when i put it into the registry (HKEY_CLASSES_ROOT\Directory\shell\PowershellMenu (Administrator)\command\(Default)) the powershell window flashes shortly.
I tried to...
...use the full PowerShell path:
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -WindowStyle Hidden -NoExit -Command "Start-Process -FilePath 'C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe' -Verb RunAs -ArgumentList #(`'-NoExit`',`'-Command`',`'Set-Location -LiteralPath `"%V`"`')";
...add a sleep to see if the -NoExit is ignored:
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -WindowStyle Hidden -NoExit -Command "Start-Process -FilePath 'C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe' -Verb RunAs -ArgumentList #(`'-NoExit`',`'-Command`',`'Set-Location -LiteralPath `"%V`"; Sleep 10`')";
without any success.
Execute in PowerShell as administrator:
'Directory',
'Directory\Background',
'Drive' | ForEach-Object {
$Path = "Registry::HKEY_CLASSES_ROOT\$_\shell\runas";
New-Item -Path $Path -Name 'command' -Force | Out-Null;
Set-ItemProperty -Path "$Path\command" -Name '(default)' -Value "PowerShell -WindowStyle Maximized -NoExit -NoLogo -Command Set-Location '%V'";
Set-ItemProperty -Path $Path -Name '(default)' -Value 'PowerShell';
Set-ItemProperty -Path $Path -Name 'HasLUAShield' -Value '';
Set-ItemProperty -Path $Path -Name 'Icon' -Value "${Env:WinDir}\System32\WindowsPowerShell\v1.0\powershell.exe,0";
}

Install msi using Start-Process with /q switch?

I want to install an msi with a /q switch, I look online and the examples don't have the /q switch and I keep getting errors.
I need something like:
$WorkingDirectory = (Split-Path $myinvocation.mycommand.path -Parent)
Start-Process -FilePath msiexec /i "$WorkingDirectory\LAPS.x64.msi" -ArgumentList /q
Don't bother with Start-Process. Use the call operator:
& msiexec.exe /i "$WorkingDirectory\LAPS.x64.msi" /q
put the whole command in the brackets
Example(Python msi):
Start-Process msiexec.exe -Wait -ArgumentList "/I $($LocalPython.FullName) /passive ALLUSERS=1 ADDLOCAL=Extensions"
replace /passive with /q
Not all installers are the same. To find the installer switches for your .msi use:
.\LAPS.x64.msi /?
.\LAPS.x64.msi -?
I would also store the msi path in a variable, and use an ArrayList for the arguments, something like this has worked for me in my scripts:
# Path to .msi
$msiPath= 'C:\LAPS.x64.msi'
# Define arguments
[System.Collections.ArrayList]$arguments =
#("/i `"$msiPath`"",
"/quiet")
# Start installation
Start-Process -FilePath msiexec.exe -ArgumentList "$arguments" -Wait -NoNewWindow
$path="C:\Dat\install.msi"
$parameters="/q"
$packageinstall=(split-path $path -leaf) + ' ' + $parameters
write-host $packageinstall
$computers = get-content c:\com.txt
$computers | where{test-connection $_ -quiet -count 1} | ForEach-Object {
copy-item $path "\\$_\c$\windows\temp" -Force -Recurse
$newProc=([WMICLASS]"\\$_\root\cimv2:win32_Process").Create("C:\windows\temp\$packageinstall")
If ($newProc.ReturnValue -eq 0) {
Write-Host $_ $newProc.ProcessId
} else {
write-host $_ Process create failed with $newProc.ReturnValue
}
}

How to capture windows command result from Start-Process?

$features = Start-Process powershell -Verb runAs -ArgumentList "Get-WindowsOptionalFeature –Online"
$features
How can I get the result back into my $feature variable?
Quick & dirty workaround: you can use temporary clixml file to store results of Get-WindowsOptionalFeature cmdlet:
$tempFile = [System.IO.Path]::GetTempFileName()
try
{
Start-Process powershell -Wait -Verb runAs -ArgumentList "-Command Get-WindowsOptionalFeature -Online | Export-Clixml -Path $tempFile"
$features = Import-Clixml -Path $tempFile
# Use $features
}
finally
{
if (Test-Path $tempFile)
{
Remove-Item -Path $tempFile -Force -ErrorAction Ignore
}
}