Run Powershell script from inside other Powershell script with dynamic redirection to file - powershell

I have been struggling with this problem and researching around but can't get a solution
My problem: I need to run a Powershell script from inside another Powershell script and redirect the output stream to a file. So far so good.
The real issue comes when I need to control the amount of logging through a variable (e.g. write only errors or only error + warning + success output streams).
I can get around it by hard-coding the command as in:
Powershell -File "\path\myscript.ps1" 2>&1> $logFilePathAndName
However, I want to give the user a couple of options for the redirect operator and want to avoid hardcoding each one of them. For that, I was thinking to just code something similar to :
$logStreams = "2>&1>"
Powershell -File "\path\myscript.ps1" $logStreams $logFilePathAndName
The last command does run my script (myscript.ps1 has no input params) but it does not write anything to the file at $logFilePathAndName.
I tried various syntax with Invoke-Command, Invoke-Expression, the call operator and Powershell -Command with no luck.
Looked at this post, had several tries but I can't just get it to work.
For example this runs my script but does not write anything to the output log:
$logStreams = "2>&1>"
$command = '"C:\myscript.ps1" $_logStreams "C:\outputlog.txt"'
iex "& $command"
Is there a way to pass a variable string for the redirect operator OR run a string containing the entire command with a variable interpolated for the output redirector ?

Your last bit there is very close, but I'm not sure why you have the underscore in there, and you need to escape your dollar sign, and close the entire thing in double quotes to cause string extrapolation.
$logStreams = "2>&1>"
$command = "'C:\myscript.ps1' $logStreams 'C:\outputlog.txt'"
iex "& $command"
I just tested that locally and it works fine.

Related

How to execute string as batch script in PowerShell

I have a string in PowerShell that I want to have executed as a batch script.
Something like:
cmd /c $batch_script
I am working with a giant cluster%!&$ software suite called Oracle Hyperion (with which most knowledge of how it operates appears to be lost - even within Oracle), so the reasons I want to do this are complex and require specific knowledge to understand, so I really just want to know if this is possible or not.
You can run a .bat file with & and then path to the bat file.
& D:\BatScripts\Example.bat
You can then also pipe that info to a string and assign it to a variable to compare against expected output etc.
$batOutput = & D:\BatScripts\Example.bat | Out-String
if($batOutput -like '*The operation completed successfully.*'){
Write-Host ("Job Complete")
} else{
Write-Host ("Job Failed")
}
Hope that helps.
Old question, but for anyone searching for the answer - this might work. Still somewhat new to PS myself, but it appears you can execute EXE files just by typing them in. But SET is an internal BATCH command, not an executable file. So executing CMD, and passing it SET, seems to work.
$Cmd = "SET"
CMD.EXE /C "$Cmd"
You should be able to build any string you want in the $Cmd variable and execute it. Not sure if the quotes around $Cmd are actually seen by CMD.EXE, so you may run into some issues where you have add quotes into the string.

Powershell Invoke-Expressions pauses

I wrote a Powershell script that uses Steam's command line tool to login and check for updates for a community server I am running. See below:
$steamcmdFolder = 'C:\download\steam'
$steamcmdExec = $steamcmdFolder+"\steamcmd.exe"
$forceinstall = 'force_install_dir'+$steamcmdFolder
$appupdate = 'app_update 258550'
$cmdOutput = "$steamcmdExec +login anonymous"
do {
Write-Host Checking for an update....
Invoke-Expression $cmdOutput
Invoke-expression $forceinstall
Invoke-expression $appupdate
}
while ($Update = 1)
The Invoke-Expression lines are individual command-line statements I want executed in the order I have them. For some reason, the first Invoke-Expression works fine but the others do not -- everything just stops. I can type in the value of $forceinstall on the PowerShell command-line and it works as expected. But why can't I do this using PowerShell? Any suggestions are welcome!
If you convert the other two lines down to what they are, it seems like they are not real commands.
#Invoke-expression $forceinstall
Invoke-Expression "force_install_dirC:\download\steam"
#Invoke-expression $appupdate
Invoke-Expression "app_update 258550"
Looking into the SteamCMD documents, it appears that you might want to change it to be a single line command.
Invoke-Expression "steamcmd +login anonymous +force_install_dir C:\download\steam +app_update 258550 +quit"

Powershell - Run external powershell script and capture output - Can't pass parameters

I have a problem running a powershell script from within another powershell script, passing parameters and capturing the output. I have tried using the ampersand operator, calling it via powershell.exe -Command but nothing seems to work.
What seems to work is using fixed parameter and values stored in a variable like this C:\path\to\script.ps1 -arg1 $value.
This may present a solution if nothing else works, but I would like to run the command similar to this & $pathToScript $params 2>&1 (the 2>&1is for capturing error output as well as standard).
Sometimes the construct prints just the path to the script,
sometimes it says Cannot run file in the middle of pipeline and sometimes it complains about it cannot find the mentioned script file (I sometimes have spaces in my path, but I thought quoting it would suffice: quoting was done like this $path = "`"C:\path\with space\to\script.ps1`"").
This is the simplified function I want to use this in:
Function captureScriptOutput
{
#the function receives the script path and parameters
param($path, $params)
#this works if no params are passed, but I need params!
$output = & $path $params 2>&1 | Out-String
}
I solved the problem with the help of a colleague.
We went a little indirection and included a cd into the respective directory and ran the command afterwards. This works like a charm.
Solution source code:
Function captureScriptOutput
{
param($fileName, $params)
cd "C:\into\path with\space"
$output = & .\$fileName $params 2>&1 | Out-String
}
This works and even captures the error output, I hope some other folks encountering this kind of problem can use this to fix their problems.
Cheerioh and thanks for reply!
Try with invoke-expression but you need test how many quote needed
Invoke-expression "$path $param"

Why won't this powershell script accept parameters?

myscript.ps1
Param(
[Parameter(Mandatory=$true,Position=1)]
[string]$computerName
)
echo "arg0: " $computerName
CMD.exe
C:\> myscript.ps1 -computerName hey
Output:
cmdlet myscript.ps1 at command pipeline position 1
Supply values for the following parameters:
computerName: ddd
arg0:
ddd
I'm simply trying to work with Powershell parameters in CMD, and I can't seem to get a script to take one. I see sites saying to precede the script with .\ but that doesn't help. I added the mandatory line to see if Powershell was reading a parameter or not, and it's clearly not. The parameter computerName is obviously the word "hey". The Param block is the very first thing in the script. Powershell appears to recognize a parameter computerName, but no matter how I enter the command, it never thinks I'm actually entering parameter.
What the heck's wrong with my syntax?
By default, Powershell will not run scripts that it just happens to find in your current directory. This is intended by Microsoft as a security feature, and I believe that it mimics behavior found in unix shells.
Powershell will run scripts that it finds in your search path. Your search path is stored in $env:path.
I suspect that you have a script named "myscript.ps1" in some other directory that is on your search path.
I have had this happen to me before. The symptom I saw was that the parameter list seemed different than what I had defined. Each script had a different parameter list, so the script bombed when I fed it a parameter list intended for the other script. My habit is to not rely on parameter position, so this problem was easy to find.
The addition of ".\" to the script ".\myscript.ps1" should force the shell to use the .ps1 file in your current directory. As a test, I would specify the full path to the file you are trying to execute (If there are spaces in the path, be sure to wrap the path in "quotes") or change it to some totally crazy name that won't be duplicated by some other file (like "crazyfishpants.ps1") and see if the shell still finds the file.
You can get into similar problems if you have a function ("Get-Foo") that is loaded out of a module or profile with the same name as a script file ("Get-Foo.ps1"). You may wind up running something other than what you intend.
Position values should be 0-based (0 for the first parameter). That said, I can't duplicate what you're seeing on either PowerShell 2.0 or 3.0.
Thank you all for your very informative responses. It looks like my question was slightly edited before I submitted it, in that the text leads you to believe that I was entering this command directly in Powershell.
I was actually running the command for the script in CMD, which totally explains why it was not passing parameters to the Powershell script. Whoever green-lighted my question probably changed C:\> to PS> thinking that I made a typo.
I assumed that if I could run the script straight from CMD, I could send parameters to it on CMD's command line, but apparently that's not the case. If I run the script in Powershell, it indeed works just fine, I'm now seeing.
My ultimate goal was to allow users to run the Powershell script from CMD. It's looking like I can make a batch file that accepts parameters, and then start powershell and send those parameters to the PS script. And so, in the batch file, I should do something like:
powershell -File C:\myscript.ps -computerName %1
This enigma was probably solved 100 times over on this site, and I apologize for the confusion. Thank you again, for your responses.

How do I write this in Powershell script?

I am very new to Powershell script.
I am trying to run a powershell script from a cmd
powershell.exe Set-ExecutionPolicy Unrestricted
powershell.exe .\startup.ps1
I need two lines within powershell script.
%WINDIR%\system32\inetsrv\appcmd.exe add apppool /name:"VCPool" /managedRuntimeVersion:"v4.0" /managedPipelineMode:"Integrated"
%WINDIR%\system32\inetsrv\appcmd.exe set app "WebRole_IN_0_VC/" /applicationPool:"VCPool"
Can I simply write it like this within the ps1 file?
& %WINDIR%\system32\inetsrv\appcmd.exe add apppool /name:"VCPool" /managedRuntimeVersion:"v4.0" /managedPipelineMode:"Integrated"
Many Thanks
Short answer, including a question: Why the hell does that need to be a PowerShell script?
You can simply create a batch file containing
%WINDIR%\system32\inetsrv\appcmd.exe add apppool /name:"VCPool" /managedRuntimeVersion:"v4.0" /managedPipelineMode:"Integrated"
%WINDIR%\system32\inetsrv\appcmd.exe set app "WebRole_IN_0_VC/" /applicationPool:"VCPool"
and run that directly instead of trying to figure out execution policies, etc.
Furthermore, appcmd should probably be in your PATH, so you can run it directly without needing to specify the full path to the program.
Longer answer, actually using PowerShell: There are two problems here.
You want to run a PowerShell script without having the appropriate execution policy set. This can be done with
powershell -ExecutionPolicy Unrestricted -File myscript.ps1
You need to adjust environment variable usage within PowerShell scripts, as % is not used to expand environment variables there. So you actually need
& $Env:WinDir\system32\inetsrv\appcmd.exe add apppool /name:VCPool /managedRuntimeVersion:v4.0 /managedPipelineMode:Integrated
& $Env:WinDir\system32\inetsrv\appcmd.exe set app WebRole_IN_0_VC/ /applicationPool:VCPool
Note also that you need an ampersand (&) before each line as a variable name in the beginning of a line switches into expression mode while you want to run a command, therefore needing command mode.
Furthermore quoted arguments can be a bit of a pain in PowerShell. PowerShell tries quoting arguments when necessary and it's not always obvious when things go wrong what actually comes out on the other end. In this case the easiest way is to not quote the arguments in any way whcih ensures that they come out correctly:
PS Home:\> args add apppool /name:VCPool /managedRuntimeVersion:v4.0 /managedPipelineMode:Integrated
argv[1] = add
argv[2] = apppool
argv[3] = /name:VCPool
argv[4] = /managedRuntimeVersion:v4.0
argv[5] = /managedPipelineMode:Integrated
PS Home:\> args set app WebRole_IN_0_VC/ /applicationPool:VCPool
argv[1] = set
argv[2] = app
argv[3] = WebRole_IN_0_VC/
argv[4] = /applicationPool:VCPool
However, if appcmd actually needs the quotes around the argument after a colon, then you need to quote the whole argument with single quotes and add the double quotes back in:
& $Env:WinDir\system32\inetsrv\appcmd.exe set app WebRole_IN_0_VC/ '/applicationPool:"VCPool"'
You might like to know you can combine the two launch statements into a single call within your CMD file:
powershell.exe -noprofile -executionpolicy unrestricted -file .\startup.ps1
The only slightly strange thing about calling appcmd.exe from PowerShell is you must surround the parameter in quotes, even if it contains no spaces. You have already done this, so yes it should work.