I am writing a script that needs to extract a ZIP file. The problem is that all the deployment machines are Windows 2008 R2 and have PowerShell 2.0 installed. I found the following code on another website that will supposedly work, however I need to do all of this from the command line rather than creating a PowerShell script.
How can I write the following code where I can call it using powershell.exe -command (New-Object System.Net.ShellApplication) for example?
$shell = New-Object -ComObject Shell.Application
$zip = $shell.NameSpace("C:\howtogeeksite.zip")
foreach($item in $zip.Items()) {
$shell.Namespace("C:\temp\howtogeek").CopyHere($item)
}
I found it on Reddit so thought I would share the answer...
powershell.exe (new-object -com shell.application).NameSpace("E:\foldername").CopyHere((new-object -com shell.application).NameSpace("E:\test.zip").Items())
You could write it directly to -Command by joining the lines with ;, ex:
powershell -NoProfile -Command $shell = new-object -com shell.application; $zip = $shell.NameSpace(“C:\howtogeeksite.zip”); foreach($item in $zip.items()) { $shell.Namespace(“C:\temp\howtogeek”).copyhere($item) }
or you could use a base64-encoded string.
powershell -?
..
# To use the -EncodedCommand parameter:
$command = 'dir "c:\program files" '
$bytes = [System.Text.Encoding]::Unicode.GetBytes($command)
$encodedCommand = [Convert]::ToBase64String($bytes)
powershell.exe -encodedCommand $encodedCommand
Ex generate command:
$command = #'
$shell = New-Object -ComObject Shell.Application
$zip = $shell.NameSpace("C:\howtogeeksite.zip")
foreach($item in $zip.Items()) {
$shell.Namespace("C:\temp\howtogeek").CopyHere($item)
}
'#
[convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes($command))
#output
JABzAGgAZQBsAGwAIAA9ACAAbgBlAHcALQBvAGIAagBlAGMAdAAgAC0AYwBvAG0AIABzAGgAZQBsAGwALgBhAHAAcABsAGkAYwBhAHQAaQBvAG4ADQAKACQAegBpAHAAIAA9ACAAJABzAGgAZQBsAGwALgBOAGEAbQBlAFMAcABhAGMAZQAoABwgQwA6AFwAaABvAHcAdABvAGcAZQBlAGsAcwBpAHQAZQAuAHoAaQBwAB0gKQANAAoAZgBvAHIAZQBhAGMAaAAoACQAaQB0AGUAbQAgAGkAbgAgACQAegBpAHAALgBpAHQAZQBtAHMAKAApACkADQAKAHsADQAKACQAcwBoAGUAbABsAC4ATgBhAG0AZQBzAHAAYQBjAGUAKAAcIEMAOgBcAHQAZQBtAHAAXABoAG8AdwB0AG8AZwBlAGUAawAdICkALgBjAG8AcAB5AGgAZQByAGUAKAAkAGkAdABlAG0AKQANAAoAfQA=
Using the encoded command:
powershell -NoProfile -encodedCommand JABzAGgAZQBsAGwAIAA9ACAAbgBlAHcALQBvAGIAagBlAGMAdAAgAC0AYwBvAG0AIABzAGgAZQBsAGwALgBhAHAAcABsAGkAYwBhAHQAaQBvAG4ADQAKACQAegBpAHAAIAA9ACAAJABzAGgAZQBsAGwALgBOAGEAbQBlAFMAcABhAGMAZQAoABwgQwA6AFwAaABvAHcAdABvAGcAZQBlAGsAcwBpAHQAZQAuAHoAaQBwAB0gKQANAAoAZgBvAHIAZQBhAGMAaAAoACQAaQB0AGUAbQAgAGkAbgAgACQAegBpAHAALgBpAHQAZQBtAHMAKAApACkADQAKAHsADQAKACQAcwBoAGUAbABsAC4ATgBhAG0AZQBzAHAAYQBjAGUAKAAcIEMAOgBcAHQAZQBtAHAAXABoAG8AdwB0AG8AZwBlAGUAawAdICkALgBjAG8AcAB5AGgAZQByAGUAKAAkAGkAdABlAG0AKQANAAoAfQA=
Related
I tried to download CCleaner using PowerShell with this command line. All I can see is a setup file is download but it is not from CCleaner.
powershell.exe -ExecutionPolicy Bypass -Command "(New-Object System.Net.WebClient).DownloadFile('https://www.ccleaner.com/ccleaner/download/standard/', (New-Object -ComObject Shell.Application).NameSpace('shell:Downloads').Self.Path + '\CCleanerUpdated.exe')"
I created a Powershell script : Download_CCleaner.ps1 that can be launched by a batch file :
Download_CCleaner.ps1
cls
$start_time = Get-Date
$Folder = "$PSScriptRoot\DownloadFolder\"
# We create a SubFolder Named "DownloadFolder" in the same path of the script if it doesn't exists yet !
If ((Test-Path -Path $Folder) -eq 0) { New-Item -Path $Folder -ItemType Directory | Out-Null }
$url = "https://download.ccleaner.com/ccsetup578.exe"
$output = $Folder + $url.Split("/")[-1]
Write-Host "`r`n Please Wait a While ... Downloading CCleaner is in Progress ..."
Invoke-WebRequest -Uri $url -OutFile $output
$Elapsed_Time = "$((Get-Date).Subtract($start_time).Minutes) Minutes(M) : $((Get-Date).Subtract($start_time).Seconds) Secondes(s)"
cls
Write-Host "`r`n Running Script Time taken is : $Elapsed_Time"
Download_CCleaner.bat
#echo off
Title CCleaner Downloader by Hackoo 2021
cls & Mode 85,7 & color 9E
echo(
echo Please Wait a While ... Trying to Download CCleaner ...
Powershell -NoLogo -ExecutionPolicy Bypass -C "./Download_CCleaner.ps1"
Timeout /T 10 /NoBreak>nul
I am facing this situation where, when i run my powershell script from PowershellISE it works as desired. But when the same script is called from a batch file the part of the powershell script with a progressbar function is written, it shows no response. I am unable to find out what is it that i am missing.
The powershell script is :
[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("System.Drawing") | Out-Null
#FUNCTION- progress bar
function progress-bar {
$Runspace = [runspacefactory]::CreateRunspace()
$PowerShell = [System.Management.Automation.PowerShell]::Create()
$PowerShell.runspace = $Runspace
$Runspace.Open()
[void]$PowerShell.AddScript({
$Form = New-Object System.Windows.Forms.Form
$Form.width = 1000
$Form.height = 200
$Form.Text = "text"
$Form.Font = New-Object System.Drawing.Font("Times New Roman" ,12, [System.Drawing.FontStyle]::Regular)
$Form.MinimizeBox = $False
$Form.MaximizeBox = $False
$Form.WindowState = "Normal"
$Form.StartPosition = "CenterScreen"
$ProgressBar = New-Object System.Windows.Forms.ProgressBar
$ProgressBar.Maximum = 100
$ProgressBar.Minimum = 0
$ProgressBar.Location = new-object System.Drawing.Size(10,70)
$ProgressBar.size = new-object System.Drawing.Size(967,10)
$ProgressBar.style = 'Marquee'
$MessagesLabel = New-Object System.Windows.Forms.Label
$MessagesLabel.AutoSize = $true
$MessagesLabel.Location = New-Object System.Drawing.Point(10,45)
$MessagesLabel.Text = "message for user"
$ShownFormAction = {
$Form.Activate()
# $Form.Dispose()
}
$Form.Add_Shown($ShownFormAction)
$Form.Controls.Add($MessagesLabel)
$Form.Controls.Add($ProgressBar)
$Form.ShowDialog()
})
$PowerShell.BeginInvoke()
}
#begin main process
progress-bar
Get-Date
Start-Sleep 5
#end main process
and the batch file which i am using to call this above script contains:
echo off
SET HomeDir=%~dp0
SET PowerShellScriptPath=%HomeDir%
PowerShell -NoProfile -ExecutionPolicy Bypass -Command "& '%HomeDir%\1.ps1'";
exit
Please help with any pointer to solution.
Try using the start command in the batch script e.g.
start powershell.exe -NoProfile -ExecutionPolicy Bypass -Command "& '%HomeDir%\1.ps1'";
This will open the powershell process in a new window and close the batch behind it, hopefully ensuring that whatever features you're using should display properly.
Update2:
Now, when I know, that x32 is the problem I debugged into the script using powershell_ise_x32 and found out, that $Word.Documents is null.
So Powershell-API for Word has a different behaviour in x32 PowerShell, then in 64bit.
Update:
The error occurs, when using PowerShell x32 and occurs NOT on PowerShell 64bit. That was really it. Powershell x32 was executed because I started it from the Total Commander 32bit.
The question is now - why 32bit and 64bit PowerShell have different behaviour?
Initial Question:
I wrote a powershell script, to convert my WordDocuments and merge them to one.
I wrote a Batch script, to start this powershell script.
When I execute the script directly in "Powershell ISE" the script works fine.
When I execute the batch script as Administrator via context menu, the script reports errors. In this case the C:\WINDOWS\SysWOW64\cmd.exe is executed.
When I execute another cmd.exe found on my system as Administrator - everything works fine:
"C:\Windows\WinSxS\amd64_microsoft-windows-commandprompt_31bf3856ad364e35_10.0.15063.0_none_9c209ff6532b42d7\cmd.exe"
Why do I have different behaviour in different cmd.exe? What are those different cmd.exe?
Batch Script:
cd /d "%~dp0"
powershell.exe -noprofile -executionpolicy bypass -file "%~dp0%DocxToPdf.ps1"
pause
Powershell Script
$FilePath = $PSScriptRoot
$Pdfsam = "D:\Programme\PDFsam\bin\run-console.bat"
$Files = Get-ChildItem "$FilePath\*.docx"
$Word = New-Object -ComObject Word.Application
if(-not $?){
throw "Failed to open Word"
}
# Convert all docx files to pdf
Foreach ($File in $Files) {
Write-Host "Word Object: " $Word
Write-Host "File Object: " $Word $File
Write-Host "FullName prop:" $File.FullName
# open a Word document, filename from the directory
$Doc = $Word.Documents.Open($File.FullName)
# Swap out DOCX with PDF in the Filename
$Name=($Doc.FullName).Replace("docx","pdf")
# Save this File as a PDF in Word 2010/2013
$Doc.SaveAs([ref] $Name, [ref] 17)
$Doc.Close()
}
# check errors
if(-not $?){
Write-Host("Stop because an error occurred")
pause
exit 0
}
# wait until the conversion is done
Start-Sleep -s 15
# Now concat all pdfs to one single pdf
$Files = Get-ChildItem "$FilePath\*.pdf" | Sort-Object
Write-Host $Files.Count
if ($Files.Count -gt 0) {
$command = ""
Foreach ($File in $Files) {
$command += " -f "
$command += "`"" + $File.FullName + "`""
}
$command += " -o `"$FilePath\Letter of application.pdf`" -overwrite concat"
$command = $Pdfsam + $command
echo $command
$path = Split-Path -Path $Pdfsam -Parent
cd $path
cmd /c $command
}else{
Write-Host "No PDFs found for concatenation"
}
Write-Host -NoNewLine "Press any key to continue...";
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown");
I've found $PSScriptRoot to be unreliable.
$FilePath = $PSScriptRoot;
$CurLocation = Get-Location;
$ScriptLocation = Split-Path $MyInvocation.MyCommand.Path
Write-Host "FilePath = [$FilePath]";
Write-Host "CurLocation = [$CurLocation]";
Write-Host "ScriptLocation = [$ScriptLocation]";
Results:
O:\Data>powershell ..\Script\t.ps1
FilePath = []
CurLocation = [O:\Data]
ScriptLocation = [O:\Script]
As to the differences between the various cmd.exe implementations, I can't really answer that. I should have thought they'd be functionally identical, but maybe there's 32/64-bit differences that matter.
The error occurs, when using PowerShell x32 and occurs NOT on PowerShell 64bit.
I debugged into the script using powershell_ise_x32 and found out, that $Word.Documents is null.
This is because on my system Word 64bit is installed.
I need to call a batch file from powershell script. The batch file name will be decided using the parameters to PS file from user. I have this code but not working as expected. Could someone poing me my mistake? Everything seems fine but I am getting issues with the actual batch file calling (one of the last 4 statements)
param(
[string]$parts
)
$sharedDrive = "\\server\share"
$cred = get-credential "DOMAIN\"
$username = $cred.UserName
$password = $cred.GetNetworkCredential().Password
$net = New-Object -com WScript.Network
$net.mapnetworkdrive("", $sharedDrive, "true", $username, $password)
$BatchFilePath = $sharedDrive + "\Public\Upgrade\Application Folder"
IF ($parts -eq "P1") {
$selectedBatchFile = "`"" + $BatchFilePath + "\P1 Upgrade File.bat" + "`""
} ELSEIF ($parts -eq "P2") {
$selectedBatchFile = "`"" + $BatchFilePath + "\P1P2 Upgrade File.bat" + "`""
} ELSE {
Write-Host "Invalid Part specified. Choose one from: P1, P2"
}
$command1 = "/k $selectedBatchFile $username $password"
## I tried all the below but NONE worked
#& cmd "`"$command1`""
#& cmd "$command1"
#Start-Process "cmd.exe" -ArgumentList "$command1"
#Start-Process "cmd.exe" -ArgumentList "`"$command1`""
Try this
Invoke-Expression "cmd /k `"$selectedBatchFile`" $username $password"
NOTE: I do not normally suggest using Invoke-Expression if it executes code from text that a user has input. For instance, think about what happens if you use Read-Host to ask the user for their username and they type in ; Remove-Item C:\ -Recurse -Force -ErrorAction 0;. Yeah, that might be a bad day for you.
On V3/V4 you could also use --% but it requires storing your info in env vars which you might not want to do with a password:
$env:file = $selectedBatchFile
$env:un = $username
$env:pw = $password
cmd.exe /c --% "%file%" %un% %pw%
See this post for more details on --%.
Is there a reason you want to start it with cmd.exe /k?
start-process -filepath $selectedbatchfile -argumentlist $username,$password
When I run a program on PowerShell it opens a new window and before I can see the output, the window closes. How do I make it so PowerShell keeps this window open?
Try doing:
start-process your.exe -NoNewWindow
Add a -Wait too if needed.
The OP seemed satisfied with the answer, but it doesn't keep the new window open after executing the program, which is what he seemed to be asking (and the answer I was looking for). So, after some more research, I came up with:
Start-Process cmd "/c `"your.exe & pause `""
I was solving a similar problem few weeks ago. If you don't want to use & (& '.\program.exe') then you can use start process and read the output by start process (where you read the output explicitly).
Just put this as separate PS1 file - for example (or to macro):
param (
$name,
$params
)
$process = New-Object System.Diagnostics.Process
$proInfo = New-Object System.Diagnostics.ProcessStartInfo
$proInfo.CreateNoWindow = $true
$proInfo.RedirectStandardOutput = $true
$proInfo.RedirectStandardError = $true
$proInfo.UseShellExecute = $false
$proInfo.FileName = $name
$proInfo.Arguments = $params
$process.StartInfo = $proInfo
#Register an Action for Error Output Data Received Event
Register-ObjectEvent -InputObject $process -EventName ErrorDataReceived -action {
foreach ($s in $EventArgs.data) { Write-Host $s -ForegroundColor Red }
} | Out-Null
#Register an Action for Standard Output Data Received Event
Register-ObjectEvent -InputObject $process -EventName OutputDataReceived -action {
foreach ($s in $EventArgs.data) { Write-Host $s -ForegroundColor Blue }
} | Out-Null
$process.Start() | Out-Null
$process.BeginOutputReadLine()
$process.BeginErrorReadLine()
$process.WaitForExit()
And then call it like:
.\startprocess.ps1 "c:\program.exe" "params"
You can also easily redirect output or implement some kind of timeout in case your application can freeze...
If the program is a batch file (.cmd or .bat extension) being launched with cmd /c foo.cmd command, simply change it to cmd /k foo.cmd and the program executes, but the prompt stays open.
If the program is not a batch file, wrap it in a batch file and add the pause command at the end of it. To wrap the program in a batch file, simply place the command in a text file and give it the .cmd extension. Then execute that instead of the exe.
With Startprocess and in the $arguments scriptblock, you can put a Read-Host
$arguments = {
"Get-process"
"Hello"
Read-Host "Wait for a key to be pressed"
}
Start-Process powershell -Verb runAs -ArgumentList $arguments
pwsh -noe -c "echo 1"