Calling bteq from Powershell - powershell

I currently generate a bat file that contains multiple BTEQ calls to execute a .btq script against a Teradata box, below is an example CMD call:
bteq <Bteq\"File_1.BTQ" >>bteq_output.txt 2>&1
The syntax as far as I understand it is:
> specifies the input file & >> specifies the output file
I am currently trying to convert the bat implementation to a PowerShell version however I get stuck with the following issue:
PS C:\...\Deploy.ps1:21 char:81
+ ... -Object { bteq < (Join-Path $deployDir $_) >> bteq_log.txt }
+ ~
The '<' operator is reserved for future use.
+ CategoryInfo : ParserError: (:) [],ParentContainsErrorRecordException
+ FullyQualifiedErrorId : RedirectionNotSupported
Which is the result of this call in my PowerShell script:
(Get-Content -Path $configFile) | Select-Object -Skip 1 | ForEach-Object { bteq.exe < (Join-Path $deployDir $_) >> bteq_output.txt }
It seems that the BTEQ command line syntax directly conflicts with the < operator in PowerShell.
EDIT
If I try to escape the < with ` then instead I am presented with the following error, as though the parameter is not picked up:
bteq.exe : *** Warning: You must log on before sending SQL requests.
At C:\...\Deploy.ps1:20 char:76
+ (Get-Content -Path $configFile) | Select-Object -Skip 1 | ForEach-Object { bteq. ...
+ ~~~~~
+ CategoryInfo : NotSpecified: ( *** Warning: Y... SQL requests. :String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError
Anyone able to shed any light as to how one would call a bteq command in PowerShell when specifying the file to be used?

in powershell
try cat <your-bteq-file> | bteq to call your bteq file

You should be able to wrap the portion in your foreach into a script block and PowerShell will treat it as one command. You would just need to begin with the & symbol.
foreach { & {bteq.exe < (Join-Path $deployDir $_) >> bteq_output.txt} }
Not being at a machine to test this you might have to dynamically build the script block as a string so your variable is resolved correctly from the loop.

Prior to seeing the answer posted by Shailesh, I managed to get it working via a call to cmd as follows:
(Get-Content -Path $configFile)[1..$fileCount] | ForEach-Object {
cmd.exe /C ([String]::Concat(" bteq <", $deployDir, "`\""" , $_ , """ >>output.txt 2>&1"))
if($LASTEXITCODE -ne 0){
Write-Host "Error Code" $LASTEXITCODE
break
} else {
Write-Host "Completed" $_ ": Return code" $LASTEXITCODE
}
};
Here this set of statement iterates over the text read from the $configFile variable, and then makes a call to bteq for each one breaking if an error code is not equal to 0.

Related

How can I send a node of xml to a script in Powershell?

I am making a powershell script that will be a shecdualed task on the server and that performs following things:
look in the export folder if there are export files older than 14 days and remove them ifso.
Calculated the date of yesterday and place it in a variable
Get a script, load it into a variable and adapt some arguments in it.
Extract a node out of the script into a variable and use it in the Cterm.exe application that starts afterwards.
Everything works, except the last step. The Cterm program starts, but asks a username and password. This is specified in the last variable with node of adapted script. It seems like he don't get that information and gets stuck. I want to send the content of the node to that last variable, but I get an error.
This is the error when I perform the code stepwise and another PowerShell session:
Method invocation failed because [System.String] does not contain a method named 'SelectSingleNode'.
At line:1 char:1
+ $inputscript = $tempfile.SelectSingleNode("//Text")
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : MethodNotFound
This is the complete script:
#Place arguments in defined variables:
$filelocation="C:\temp" #E on the servers
$exportdestination="C:\temp"
$tempfile= ("D:\temp\temp-file.txt")
Write-Output $filelocation
$instanceName="GCS"
#Check if there are files (in the output folder) older then 14 days and remove them:
$limit = (Get-Date).AddDays(-15)
# Delete files older than the $limit.
$removedfile= Get-ChildItem -Path $exportdestination -Recurse -Force | Where-Object { !$_.PSIsContainer -and $_.CreationTime -lt $limit }
try {
$removedfile | remove-Item -Force
}
catch {
{Write-Output "error: Not all the files could be removed!"}
}
#Export the file with the data of yesterday using the RAT script:
$yesterday=(Get-Date).AddDays(-1).ToString("yyyy-MM-dd")
write-output "hello world"
$script= [xml](Get-Content C:\CTWS_export_infinity_v1.6.04.dms)
write-output "hello world"
$script -Replace ':startDate', $yesterday -Replace ':endDate', $yesterday -Replace ':filename', ($exportdestination+"\"+$instanceName)| Out-File -FilePath $tempfile
write-output "hello world"
#| Set-Content C:\CTWS_export_infinity_v1.6.04_$yesterday.dms
#$scripttemp = C:\CTWS_export_infinity_v1.6.04_$yesterday.dms
#Start-Process -FilePath "D:\CobasInfinity\HealthShare\bin\CTerm.exe" -ArgumentList #("/console=cn_ap:$instanceName $filelocation\temp-file.txt _SYSTEM INFINITY") -wait
$inputscript = $tempfile.SelectSingleNode("//Text")
& "D:\CobasInfinity\HealthShare\bin\CTerm.exe" /console=cn_ap:$instanceName $inputscript
#Remove-Item -Path $tempfile
How can I solve that final error?
I tried to save the content as an xml in the variable,
I tried to select one node of that variable,
I used 'hello world' prints to follow the progress of the script,
I tried to check the script by doing it step by step in another PowerShell session to see where to problem is.
How can I solve that final error?

PowerShell - Use Dynamically Created Variable Name Within a Variable Name

So I have a powershell script that I am trying to get up and running. Most of it works but what I am trying to do to make it as easy as possible to run periodically is to have it reference a list of numbers (IPs) in a text file, and then create a new variable for each line of the text file. This part does work using the following.
$iplist = get-content c:\powershell\ips.txt | where-object { $_.Trim() -ne '' }
$startnum = 0
foreach($line in $iplist){
$startnum++
new-variable -name "ip$startnum" -Value $line -Force
}
This is great, but later on in the script it has to use the number stored in each of those dynamically created variables in two other parts of the script. One part is where is reverses the IP address and then stores its reversed variant in another variable, and on another part it uses that reversed IP address as part of a lookup using [System.Net.DNS].
So basically, using that first snippet of code the script does the following, using a text file called ips.txt with 1.2.3.4 on the first line and 5.6.7.8 on the second line
$ip1 = 1.2.3.4
$ip2 = 5.6.7.8
Then I want to take those $ip1 and $ip2 values and reverse them. I know the reverse part works cause it works with a static input, but when i try it with variables it doesn't work, below is a snippet of the code i'm trying to do this with. Its basically an updated version of the code snippet from above.
$iplist = get-content c:\powershell\ips.txt | where-object { $_.Trim() -ne '' }
$startnum = 0
foreach($line in $iplist){
$startnum++
new-variable -name "ip$startnum" -Value $line -Force
new-variable -name "ipParts$startnum" -Value "$ip$startnum".Split('.')
[array]::Reverse($ipParts$startnum)
$ipparts$startnum = [string]::join('.',$ipParts$startnum)
}
When I run that though I get the following errors
At line:8 char:30
+ [array]::Reverse($ipParts$startnum)
+ ~
Missing ')' in method call.
At line:8 char:30
+ [array]::Reverse($ipParts$startnum)
+ ~~~~~~~~~
Unexpected token '$startnum' in expression or statement.
At line:4 char:26
+ foreach($line in $iplist){
+ ~
Missing closing '}' in statement block or type definition.
At line:8 char:39
+ [array]::Reverse($ipParts$startnum)
+ ~
Unexpected token ')' in expression or statement.
At line:9 char:53
+ $ipparts.$startnum = [string]::join('.',$ipParts$startnum)
+ ~
Missing ')' in method call.
At line:9 char:53
+ $ipparts.$startnum = [string]::join('.',$ipParts$startnum)
+ ~~~~~~~~~
Unexpected token '$startnum' in expression or statement.
At line:9 char:62
+ $ipparts.$startnum = [string]::join('.',$ipParts$startnum)
+ ~
Unexpected token ')' in expression or statement.
At line:10 char:1
+ }
+ ~
Unexpected token '}' in expression or statement.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : MissingEndParenthesisInMethodCall
There are two parts to this, but i'm hoping if I can figure out this first part then the second part when I use the final value that is supposed to be stored in $ipParts$startnum to do the lookups will be easier.
EDIT
So I had an idea and change the script to this
$iplist = get-content c:\powershell\ips.txt | where-object { $_.Trim() -ne '' }
$startnum = 0
foreach($line in $iplist){
$startnum++
new-variable -name "ip$startnum" -Value $line -Force -ErrorAction SilentlyContinue
new-variable -name "ipParts$startnum" -Value "$ip$startnum".Split('.')
$iptemp = get-variable -name "ipparts$startnum"
[array]::Reverse("$iptemp")
$iptemp = [string]::join('.',"$iptemp")
set-variable -name "ipParts$startnum" -Value "$iptemp"
}
write-host "iplist is $iplist......ip1 is $ip1....ip2 is $ip2....ipparts1 is $ipparts1.......ipparts2 is $ipparts2....iptemp value is $iptemp"
Basically use set-variable to modify it as a string with other variable names in it, kind of works, but when i did write-host on the last part to make sure its actually writing the proper values to the variables, on $ipparts1, $ipparts2, and $iptemp, i have the following value
"System.Management.Automation.PSVariable"
I'm not entirely sure what that means.

Powershell excluding only files

I have the following error when running a script in powershell in version 5.1
Below my simple script to delete files over 180 days, I've tried some solutions but I haven't found what may be the error.
(Below error translated from Portuguese to English)
"Out-File: It is not possible to validate the argument in the 'Encoding' parameter. The" files \ DeleteLogFile_21_01_2020.log "argument does not belong to the set" unknown; string; unicode; bigendianunicode; utf8; utf7; utf32; ascii; default; oem "specified by the ValidateSet attribute. Provide an argument that is in the set and try the command again. On the line: 1 character: 36 + $ Log | Out-File -Append D: \ Program files \ DeleteLogFile_ $ LogDate.log + ~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ CategoryInfo: InvalidData: (:) [Out-File], ParameterBindingValidationException + FullyQualifiedErrorId: ParameterArgumentValidationError, Microsoft .PowerShell.Commands.OutFileCommand "
$logPath = "D:\Program files\NICE Systems\Logs"
$nDays = 10
$startTime = Get-Date
$Extensions = "*.*"
$LogDate = (Get-Date).ToString("dd_MM_yyyy")
$Files = Get-Childitem $LogPath -Include $Extensions -Recurse | Where-Object {$_.LastWriteTime -le (Get-Date).AddDays(-$nDays)}
foreach ($File in $Files)
{
if ($NULL -ne $File )
{
$Log = "`nData e Hora da Deleção: " + $startTime + ". O arquivo " + $File + " foi deletado do sistema."
$Log | Out-File -Append D:\Program files\DeleteLogFile_$LogDate.log
Remove-Item $File.FullName | out-null
}
}
You have no quotes around the path to your log file so it's cutting it off at the first space. You can use double quotes and the variable will still be expanded. Single will not be.
$Log | Out-File -Append "D:\Program files\DeleteLogFile_$LogDate.log"
By default windows will also not allow you to write to the program files folder and this is generally not good practice.
On your Out-File line, your path has a space in it and is not surrounded with quotation marks. In PowerShell, and most scripting languages for that matter, you have to take into account Positional Parameters. Any space that is not in a string or is not followed by/preceded by a parameter (eg. -FileName C:\FileName.txt), will be assumed to precede a positional parameter.
With that said, it is trying to use "D:\Program" as the path, and "files\DeleteLogFile_$LogDate.log" as the encoding type, which is obviously not valid. To fix this, simply make the path a string by putting it in quotation marks like so:
$Log | Out-File -Append "D:\Program files\DeleteLogFile_$LogDate.log"

How to replace multiple strings in a text file and generate the logfile simultaneously?

There are multiple text files in a folder and there are multiple affected IDs in each text file. I need to replace them with new IDs. Also, I want to generate a text log file listing the filename,oldID,newID . This log file is required for crosschecking and validation.
I have a csv file from which I am creating a array IdList. I have listed the part of code for replacing the string below.
foreach ($f in gci -r -include "*.txt")
{
Set-Variable -Name filename -value ($f.name)
for( $i=0; $i -le $elementCount; $i++)
{
Write-Host $i
$oldString= $IdList[$i].OLD_ID+','+$IdList[$i].OLD_ID_TYPE
$newString= $IdList[$i].NEW_ID+','+$IdList[$i].NEW_ID_TYPE
gc $f.fullname|ForEach-Object {if($_.contains($oldString)){ "$filename,$oldString,$newString" >> $logFile; $_ -replace $oldString,$newString}}| sc $f.fullname
}
}
I am getting error :
Set-Content : The process cannot access the file 'U:\testScript\rapg6785.txt' because it is being used by another process.
At line:22 char:152
+ gc $f.fullname|ForEach-Object {if($_.contains($oldString)){ "$filename,$oldString,$newString" >> $logFile; $_ -replace $oldString,$newString}}| sc <<<< $f.fullname
+ CategoryInfo : NotSpecified: (:) [Set-Content], IOException
+ FullyQualifiedErrorId : System.IO.IOException,Microsoft.PowerShell.Commands.SetContentCommand
try putting gc $f.fullname in brackets: (gc $f.fullname).
In this way the pipeline starts when gc ends to read the file and free the file handle to be used by another process.

How to pipe all output of .exe execution in Powershell?

In Powershell I am running psftp.exe which is PuTTy's homepage. I am doing this:
$cmd = "psftp.exe"
$args = '"username#ssh"#ftp.domain.com -b psftp.txt';
$output = & $cmd $args
This works; and I am printing out $output. But it only catches some output in that variable (like "Remote working directory is [...]") and is throwing other output to an error type like this:
psftp.exe : Using username "username#ssh".
At C:\full_script.ps1:37 char:20
+ $output = & <<<< $cmd $args
+ CategoryInfo : NotSpecified: (Using username "username#ssh".:String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError
This "Using username ..." etc looks like a normal FTP message. How can I make sure all output gets put into $output?
The problem is some output is being sent to STDERR and redirection works differently in PowerShell than in CMD.EXE.
How to redirect output of console program to a file in PowerShell has a good description of the problem and a clever workaround.
Basically, call CMD with your executable as a parameter. Like this:
UPDATE
I fixed my code so it would actually work. :)
$args = '"username#ssh"#ftp.domain.com -b psftp.txt';
$output = cmd /c psftp.exe $args 2`>`&1
Give this a try
$output = [string] (& psftp.exe 'username#ssh#ftp.domain.com' -b psftp.txt 2>&1)
There is a PowerShell bug about 2>&1 making error records. The [string] cast works around it.
& "my.exe" | Out-Null #go nowhere
& "my.exe" | Out-Default # go to default destination (e.g. console)
& "my.exe" | Out-String # return a string
the piping will return it in real-time
& "my.exe" | %{
if ($_ -match 'OK')
{ Write-Host $_ -f Green }
else if ($_ -match 'FAIL|ERROR')
{ Write-Host $_ -f Red }
else
{ Write-Host $_ }
}
Note:
If the executed program returns anything other than a 0 exitcode, the piping will not work. You can force it to pipe with redirection operators such as 2>&1
& "my.exe" 2>&1 | Out-String
sources:
https://stackoverflow.com/a/7272390/254276
https://social.technet.microsoft.com/forums/windowsserver/en-US/b6691fba-0e92-4e9d-aec2-47f3d5a17419/start-process-and-redirect-output-to-powershell-window