Running a command with arguments assistance - powershell

I have a command which runs a program in silent mode, it uses an XML file for the data repository and a word template to create multiple word documents based on a filter xml file.
The command I use is:
"P:\ath to\executable" -Username:Admin -Password:Pa55w0rd -Datadefinition:"C:\Data.xml" -Datafilter:"C:\Filter.xml" -wordtemplate:"C:\Batch\Paul1.dotx" -Targetdocument:="C:\Batch\Paul1.pdf" -filetype:PDF -Log:"C:\Logs\error.log" -Usage:DOCGENSILENT
I need to run this as a PowerShell script which I have mostly managed:
set-executionpolicy unrestricted
$datadefinition = Get-Content "C:\Data file.xml"
$datafilter = Get-Content "C:\Filter for data file.xml"
$wordTemplate = Get-Content "C:\"C:\Template\Paul1.dotx"
$targetFolder = Get-Content "C:\"C:\Paul\Paul.pdf"
Stop-Job = "Executable path" -Username:Admin -Password:Pa55w0rd -Datadefinition:%dataDefinition% -Datafilter:%dataFilter% -wordtemplate:%wordTemplate% -Targetdocument:%targetFolder% -filetype:docx -Log:%logPath% -Usage:DOCGENSILENT
Stop-Job 1
set-executionpolicy restricted
Write-Host -NoNewLine "Press any key to continue..."
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
My issue is that the script starts the executable but then doesnt pass the Variables, can anyone guide me in the right direction to fix this?

Getting this working depends on the behavior of your executable. Some things I noticed:
Shouldn't this:
$wordTemplate = Get-Content "C:\"C:\Template\Paul1.dotx"
be this:
$wordTemplate = "C:\Template\Paul1.dotx"
Are you sure you need Get-Content? (Aside from that, the path and quoting in your sample are not correct.)
Shouldn't this:
$targetFolder = Get-Content "C:\"C:\Paul\Paul.pdf"
be this:
$targetDocument = "C:\Paul\Paul.pdf"
I doubt Get-Content is correct here, since presumably your output file doesn't exist yet? I also renamed the variable so it makes more sense in your command.
In fact, are you sure you need Get-Content for any of those? Aren't you specifying filenames, not the content of the files?
In PowerShell, variables are prefixed with $ rather than being surrounded by %.
Using Set-ExecutionPolicy within a script to enable scripts to run is pointless, because the script is already running. (That is, if execution policy prevented script execution, PowerShell wouldn't let you run the script in the first place.)
If my guesses regarding your variables are correct, I think your script should look something like this (note also that I specified a $logFile variable, which I didn't see in your script):
$datadefinition = "C:\Users\Administrator\data\Sample Model_146_object type(s).xml"
$datafilter = "C:\Users\Administrator\data\Sample Model_146_object type(s).xml"
$wordtemplate = "C:\Users\Administrator\Templates\Base object.docx"
$targetdocument = "C:\Users\Administrator\Result\sample test15"
$logfile = "C:\Users\Administrator\Logs\C4W Error.log"
& "C:\Program Files (x86)\Communicator4Word.exe" -Username:Admin -Password: -Datadefinition:$datadefinition -Datafilter:$datafilter -wordtemplate:$wordtemplate -Targetdocument:$targetdocument -filetype:docx -Log:$logfile -Usage:DOCGENSILENT
I don't know the behavior of Communicator4Word.exe when you use -Password: with no password after it. (Is that a syntax error, or should you just omit -Password: altogether?)

Related

How do I run a PowerShell script on a file from the context menu?

I have written a PS script, which replaces a specific string at the beginning of the file, adds another piece of string to the end of the file, and finally it puts out an XML.
My code might be ugly (I am not a programmer/engineer or anything, just trying to make life easier for some family members who are running a small business), but it works:
$content = Get-Content -Path 'C:\Users\blabla\Desktop\4440341930.txt'
$newContent = $content -replace 'text to be replaced','this is going to replace stuff'
$newContent | Set-Content -Path 'C:\Users\blabla\Desktop\4440341930.txt'
Add-Content C:\Users\blabla\Desktop\4440341930.txt '</Items>'
$x = [xml](Get-Content "C:\Users\blabla\Desktop\4440341930.txt")
$x.Save("C:\Users\blabla\Desktop\4440341930.xml")
I would like them to be able to run this script from the context menu, by right clicking on a txt file. I did a little research and I kind of get what I have to add to Registry, however, I'm not sure how to make it work. Since the path of each file that they are going to right click on is going to be different, the path that I'm specifying in $content is not going to work.
What do I have to modify in my code to be able to add it to the Registry?
To accomplish this you need to:
Create a Shortcut in the SendTo Folder: "$DestinationPath\AppData\Roaming\Microsoft\Windows\SendTo"
The target: "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"
The Arguments: -File "d:\path\your PS1 file"
In your program read the file name passed by Explorer as:
Param
(
[Parameter(Mandatory=$false)]
[String] $FilePath
)
I've written a Setup Function that accomplishes steps 1-3 that I include in all my programs that I want on the context menu and then just run the program with the -Setup switch. We're not supposed to post developed code here, but if you can't figure it out let me know and I'll post it and hope I don't get killed for it. LOL!
UPDATE:
If you want to pass more than one file you need to process the files a little differently. Delete the Param block above and then use this type of code to retrieve the files.
If ($Args.count -eq 0) {
$Message = "No Files were passed from File Explorer."
[Void]$MsgBox::Show(
"$Message","System Exit",$Buttons::OK, $MBIcons::Stop)
Show-PowerShell
Exit #Comment out for testing from ISE!
}
Else {
$FilesToCopy = $Args
}

Running .exe to get String output is not saving to string variable

Forgive me, I am new to PowerShell in general. I'm updating a build process that works on Linux (in bash) to one that will work on Windows in PowerShell.
My goal is to get the version of the game engine currently present on the build system. The default build location is well-known, so we try to execute it and get the version, like so:
$Version = & 'C:\Program Files\LOVE\love.exe' --version
When this executes, the $Version value is empty:
Write-Output $Version
[no output]
$Version -Eq $True
False
If I run my executable directly from the shell, I notice the line is not presented on a newline:
PS C:\Users\robbm\Myproject\Mygame> $Version = & 'C:\Program Files\LOVE\love.exe' --version
PS C:\Users\robbm\Myproject\Mygame> LOVE 11.3 (Mysterious Mysteries)
This makes me suspect there is some strange output behavior with the executable in the first place.
Is this a problem with LÖVE's --version output, or am I misunderstanding something about redirecting outputs in PowerShell? I've tried a few things to capture output, and $Version always seems to end up a nil value, such as:
$Version = & '\\build\love\love.exe' '--version' | Out-String
Write-Output $Version
$Version = (& '\\build\love\love.exe' '--version' | Out-String)
Write-Output $Version
Help is appreciated. As this works for other cmdlets, I'm inclined to believe it might be a function of LÖVE, but I'd appreciate thoughts as to how I could work with this anyway, or any method in which to capture the version it's clearly outputting to the screen when I execute it directly regardless.
EDIT:
LÖVE definitely does something different in regards to running on Windows. Looking at the version printing source, we are working with the aptly-named LOVE_LEGENDARY_CONSOLE_IO_HACK enabled on Windows, which appears to open a new console entirely, perhaps in cmd and write out there.
Doing the suggestions of commenters, I tried doing the .Exception.Message method, but there is none when called like so:
$Version = &('C:\Program Files\LOVE\love.exe' '--version').Exception.Message
So I'm still looking for ways to make this work within the confines of LÖVE hacking together some strange I/O stream.
EDIT2:
Another fun fact, redirection to a file similarly fails:
PS> (&'C:\Program Files\LOVE\love.exe' '--version') 2>&1 > .\love.txt
PS> LOVE 11.3 (Mysterious Mysteries)
PS> cat .\love.txt
[empty]
So this looks to be overly hacky on behalf of LÖVE, not an issue with PowerShell.
After reading your last edit, this probably won't help you, but may help others.
You could try to capture the output like this:
function runCmdAndCaptureOutput(
[Parameter(Mandatory=$true)]
[string] $cmd
) {
[string] $errOut
[string] $stdOut
# Deliberately dropped '$' from vars below.
Invoke-Expression $cmd -ErrorVariable errOut -OutVariable stdOut
if($LASTEXITCODE -ne 0) {
Write-Host -ForegroundColor Red "LASTEXITCODE: $LASTEXITCODE"
throw $LASTEXITCODE
}
return $stdOut
}
$exeCmd = "'C:\Program Files\LOVE\love.exe' --version"
$output = runCmdAndCaptureOutput -cmd $exeCmd
Write-Host $output

What is the way to escape colon in powershell?

I have the following powershell in a script file:
cd "$env:systemdrive:\$env:APPDATA\Mozilla\Firefox\Profiles\*.default"
Expanded, I want this to do something similar to this:
cd "C:\Users\Bob\AppData\Roaming\Mozilla\Firefox\Profiles\f1wkii3l.default"
But when I run it, I get:
cd : Cannot find drive. A drive with the name '\C' does not exist.
I am guessing the colon I put in there to be at the end of C:\ is causing problems.
I tried:
cd "${env:systemdrive}:\${env:APPDATA}\Mozilla\Firefox\Profiles\*.default"
But then I get the error:
cd : Cannot find a provider with the name 'C'.
How can I escape the colon so that powershell just sees it as normal text?
NOTE: I looked at this question: Escaping a colon in powershell and the answer is all about .NET and does not answer my question (though the question is very similar).
Other answers are valid for troubleshooting and for your task at hand. One suggestion I have, and what I consider a best-practice, is making use of Join-Path anytime you are dealing with paths so you don't have to worry about trailing or beginning path separators.
This example
$d1 = "${env:APPDATA}\Mozilla\Firefox\Profiles\*.default"
$d2 = Join-Path ${env:APPDATA} "\Mozilla\Firefox\Profiles\*.default"
$d3 = Join-Path ${env:APPDATA} "Mozilla\Firefox\Profiles\*.default"
Write-Output "d1 = '$d1'"
Write-Output "d2 = '$d2'"
Write-Output "d3 = '$d3'"
Produces
d1 = 'C:\Users\xxx\AppData\Roaming\Mozilla\Firefox\Profiles\*.default'
d2 = 'C:\Users\xxx\AppData\Roaming\Mozilla\Firefox\Profiles\*.default'
d3 = 'C:\Users\xxx\AppData\Roaming\Mozilla\Firefox\Profiles\*.default'
All are acceptable, and I would tend to use the d3 version in my own scripts.
You don't need to escape anything there. The APPDATA environment variable already includes the drive, so you only need
cd "${env:APPDATA}\Mozilla\Firefox\Profiles\*.default"
${env:systemdrive}:\${env:APPDATA} would create a path C:\C:\Users\..., which is indeed invalid.
If you write-host those environmental variables, you'll see that:
PS C:\>write-host $env:systemdrive
C:
PS C:\>write-host $env:appdata
C:\Users\****\AppData\Roaming
So your current attempt expands to C:C:\Users\****\AppData\Roaming\...
So all you need is the command:
cd "$env:Appdata\Mozilla\Firefox\Profiles\*.default"

Display progress of exe installation from powershell?

I'm installing a file through powershell silently, but would like to give feedback on the progress of the installation. I can't seem to find this information anywhere. This is the code I have for running the exe:
$exe = "wls1033_oepe111150_win32.exe"
$xmlLocation = Resolve-Path "silent_install.xml"
$xmlLocation = "-silent_xml=" + $xmlLocation
$installLogLoc = Resolve-Path "wls_install.log"
$installLogLoc = "-log=" + $installLogLoc
$AllArgs = #('-mode=silent', $xmlLocation, $installLogLoc)
$filePath = Resolve-Path $exe
$p = New-Object System.Diagnostics.Process
$p.StartInfo.Filename = $filePath
$p.StartInfo.Arguments = $AllArgs
$p.Start();
$p.WaitForExit();
Is there even a way to do this? I do get a progress meter for the extraction process in an alternate command window that installs the exe, but other than that it sits for there about 10 minutes with no sort of indication.
Edit: So seeing as this isn't possible, is there a way to do an asynchronous pipeline call while running the exe?
Thanks
Please correct me if I'm wrong, but I'm 99% sure that this is NOT possible. Your exe file is seperate process and not a PowerShell script. It will not be able to pass status messages to your PowerShell sessions. The only possibility would be to detect the setups log-file, tail it and update a progressbar in PowerShell based on keywords from the log. This is however a big task and something you need to customize for each setup file.
I would try to look into your exe file and see if it has a "basic ui" (or a similar type) mode that you can use instead of the silent option. A last alternative would be to repackage the setup with such an option(making installation automated with only progressbar). This solution would still only show the progressbar in a separate window and not in PowerShell itself.

Powershell running under a service hangs on *.zip CopyHere

I'm running a Windows Service (Hudson) which in turn spawns a PowerShell process to run my custom PowerShell commands. Part of my script is to unzip a file using CopyHere. When I run this script locally, I see a progress dialog pop up as the files are extracted and copied. However, when this runs under the service, it hangs at the point where a dialog would otherwise appear.
Here's the unzip portion of my script.
# Extract the contents of a zip file to a folder
function Extract-Zip {
param([string]$zipFilePath, [string]$destination)
if(test-path($zipFilePath)) {
$shellApplication = new-object -com shell.application
$zipFile = get-item $zipFilePath
$zipFolder = $shellApplication.NameSpace($zipFile.fullname)
$destinationFile = get-item $destination
$destinationFolder = $shellApplication.NameSpace($destinationFile.fullname)
$destinationFolder.CopyHere($zipFolder.Items())
}
}
I suspect that because its running under a service process which is headless (no interaction with the desktop), its somehow stuck trying to display a dialog.
Is there a way around this?
If it's still actual, I managed to fix this with having CopyHere params equal 1564.
So in my case extract zip function looks like:
function Expand-ZIPFile{
param(
$file, $destination
)
$shell = new-object -com shell.application
$zip = $shell.NameSpace($file)
foreach($item in $zip.items())
{
$shell.Namespace($destination).copyhere($item,1564)
"$($item.path) extracted"
}
1564 description can be found here - http://msdn.microsoft.com/en-us/library/windows/desktop/bb787866(v=vs.85).aspx:
(4) Do not display a progress dialog box.
(8) Give the file being operated on a new name in a move, copy, or rename operation if a file with the target name already exists.
(16) Respond with "Yes to All" for any dialog box that is displayed.
(512) Do not confirm the creation of a new directory if the operation requires one to be created.
(1024) Do not display a user interface if an error occurs.
If this is running on Vista or Windows 7, popping up UI from a service isn't going to be seen by the end user as you suspected. See this paper on Session 0 Isolation. However, does the progress dialog require user input? If not, I wouldn't think that would cause the service to hang. I would look for an option to disable the progress display. If you can't find that, then try switching to another ZIP extractor. PSCX 1.2 comes with an Expand-Archive cmdlet. I'm sure there are also others available.
Looking at the documentation for PowerShell, it looks like the -NonInteractive option may help here