How to fix line breaks? - powershell

I'm kind of new to PowerShell and I need to fix a bank statement file. The problem is that this file has a CNAB 240 standard, however, it comes with a line break, so we have to fix it manually.
I have a script that makes this correction, however, I can't make it run alone because I need to use CMD to run PowerShell.
My idea is to use this script in the task manager to look for the .txt file and fix it, does anyone have any ideas?
Follow the script:
if ($args.count -eq 0)
{
Write-Error "Please enter a file to read"
return
}
$file = $args[0]
if(![System.IO.File]::Exists($file))
{
Write-Error "File not found: $file"
return
}
$expectedsize = 240
$lastSize = 0
foreach($line in [System.IO.File]::ReadLines($file))
{
if ($line.length -gt 0)
{
if (!($row.length -eq $expectedsize) -And (($row.length + $lastSize) -eq $expectedsize))
{
Write-Host -NoNewLine $linha
$lastSize += $line.length
}
else
{
if ($lastSize -gt 0)
{
Write-Host
}
Write-Host -NoNewLine $linha
$lastSize = $line.length
}
}
else
{
Write-Host
}
}
The script above makes the normal correction of the file, however, I am not able to make it follow the steps below:
Browse the txt file
Validate that it does not have the 240 positions in each line
And then make the correction

Related

PowerShell Trying to compare .Length of $Variable in Excel Worksheets

I am working on piece of a powershell script to interact with a directory of excel documents. I have a for each loop to loop through each of the files in a directory open them to then copy and paste the DataBodyRange of listobject(1) to my main document. As stated in the title my issue is as follows: The If($shippedVal.Length -gt 0) statement will not proceed. As if the $shippedVal actually contains no value. When I try to Write-Host $shippedVal the IDE stalls.
Here is the code in question:
foreach($f in $clientPath){
$clientFile = $f.FullName
$clientWorkbook = $excel.Workbooks.open($clientFile)
$clientWorksheet = $clientWorkbook.Worksheets
Write-Host $clientFile
foreach ($ws in $clientWorksheet)
{
Write-Host $ws.Name + "Attempting List Object Count"
If($ws.ListObjects.Count -gt 0)
{
Write-Host "Made it to copy range"
$clientLR = ($ws.UsedRange.Rows.Count +1)
$shippedVal = $ws.ListObjects(1).DataBodyRange.Cells(1)
If($shippedVal.Length -gt 0)
{
Write-Host "Made it to line 41"
$shippedBreakdown = $ws.ListObjects(1).DataBodyRange
$pasteLoc = $mainWorksheet.Range("A" + "&" + $mainLR)
$shippedBreakdown.Copy() | out-null
$mainWorksheet.Paste($pasteLoc)
$mainLR = ($mainWorksheet.UsedRange.Rows.Count + 1)
Write-Host "Pasting DataBodyRange"
}
}
}
$clientWorkbook.Close
}
If you need any additional information please let me know.

Powershell - Fix Line Break

I have a situation here and I would like to share it with you to ask for help.
I have a TXT file that I receive every day and I need to import it into my ERP, however, this file comes with a line break that we have to manually adjust
And when adjusted, it looks like this:
{
Write-Error "Informe um arquivo para leitura"
Return
}
$arquivo = $args[0]
if(![System.IO.File]::Exists($arquivo))
{
Write-Error "Arquivo nao encontrado: $arquivo"
Return
}
$tamanhoEsperado = 240
$ultimoTamanho = 0
foreach($linha in [System.IO.File]::ReadLines($arquivo))
{
if ($linha.length -gt 0)
{
if (!($linha.length -eq $tamanhoEsperado) -And (($linha.length + $ultimoTamanho) -eq $tamanhoEsperado))
{
Write-Host -NoNewLine $linha
$ultimoTamanho += $linha.length
}
else
{
if ($ultimoTamanho -gt 0)
{
Write-Host
}
Write-Host -NoNewLine $linha
$ultimoTamanho = $linha.length
}
}
else
{
Write-Host
}
}
But I am not able to make the process automatic with this script.
Powershell will look for the TXT file in a specific folder, validate if the file has 240 positions and if not, correct that line break shown in img1. Would that be possible?
Note:
Write-Host is typically the wrong tool to use, unless the intent is to write to the display only, bypassing the success output stream and with it the ability to send output to other commands, capture it in a variable, or redirect it to a file. To output a value, use it by itself; e.g., $value instead of Write-Host $value (or use Write-Output $value). See this answer for more information.
Therefore, your code only produced for-display output, not data.
Try something like the following:
$fragment = ''
$correctedLines =
foreach ($line in [System.IO.File]::ReadLines($arquivo)) {
if ($fragment) { # The previous line was incomplete.
$fragment + $line # Concatenate the fragment with the current line and output.
$fragment = '' # Reset the fragment variable.
} elseif ($line.Length -ne 240) {
$fragment = $line # Save the fragment and continue.
} else {
$line # Complete line -> output it.
}
}
Note the use of implicit output (e.g., $line) and that you can directly collect all output from the foreach statement in a variable.

ArrayList not displaying when first referenced in function

Facing a couple logistical issues in PowerShell - clearly I'm missing a basic concept:
Setup: Create the menu.ps1 file (shown below), launch PowerShell 7.2.2 and call the file locally.
Issues:
The first time you choose option 1 for the ArrayList ($psArrayList), it does not display (although we see from the initial screen load that the items are populated). If you return to the menu and choose option 1 again, it will display on the second pass. ($psArray does load fine on first try, so is this is a type issue.?)
When the script ends, $psArrayList and $psArray are still in the current session variables, as indicated by: Get-Variable psArray*. Even if I instantiate them with $script:psArrayList = [System.Collections.ArrayList]#() and $script:psArray = #() they seem to stay within the session scope. Is there a "right" way to clear them when the ps1 ends?
menu.ps1 contents:
$psArrayList = [System.Collections.ArrayList]#()
# example of populating later in function etc...
$psArrayList.Add([pscustomobject]#{name="bird";color="blue"})
$psArrayList.Add([pscustomobject]#{name="cat";color="orange"})
$psArrayList.Add([pscustomobject]#{name="bear";color="brown"})
$psArray = #()
# example of populating later in function etc...
$psArray += "dog"
$psArray += "fish"
$psArray += "squirrel"
function End-Script {
Remove-Variable psArray*
Exit
}
function Display-Menu {
[int]$choice=-1
Write-Host "This is a menu..." -ForegroundColor Green
Write-Host "Here are your options:"
Write-Host
Write-Host "`t1 - ArrayList"
Write-Host "`t2 - Array"
Write-Host "`t0 - quit (do nothing)"
Write-Host
while ($choice -lt 0) { $choice= Read-Host -Prompt "Choose 1-2 (or 0 to quit)" }
Process-Menu($choice)
}
function Process-Menu([int]$choice) {
switch($choice) {
1 { Write-Host "You chose ArrayList:"; Write-Output $psArrayList }
2 { Write-Host "You chose Array:"; Write-Output $psArray }
0 { Write-Host "You chose to quit. Exiting."; End-Script }
}
$yn=""
while ($yn -eq "") { $yn= Read-Host -Prompt "Return to main menu? (y/n)" }
if ($yn -eq "y") { Display-Menu } else { Write-Host "Ending..."; End-Script }
}
Display-Menu
Regarding the first issue, you would need to use Out-Host or Out-Default so that both outputs (Write-Host together with the arrays) are correctly displayed to the console. See these helpful answers for in depth details on this:
https://stackoverflow.com/a/50416448/15339544
https://stackoverflow.com/a/34858911/15339544
Regarding the second issue, your End-Script function would have a scope issue, Remove-Variable is trying to remove variables defined inside the function's scope (Local), if you want to target the variables defined outside it (Script), you would need to use the -Scope parameter, for example:
function End-Script {
Get-Variable psArray* | Remove-Variable -Scope Script
# `Remove-Variable psArray* -Scope Script` would be valid too
}
From the cmdlet's Parameters section we can read the following for the -Scope parameter:
A number relative to the current scope (0 through the number of scopes, where 0 is the current scope and 1 is its parent)
In that sense, -Scope 1 would also work.
Below you can see an example of your script with some improvements as well as input validation:
$psArrayList = [System.Collections.ArrayList]#()
$psArrayList.AddRange(#(
[pscustomobject]#{name="bird";color="blue"}
[pscustomobject]#{name="cat";color="orange"}
[pscustomobject]#{name="bear";color="brown"}
))
$psArray = "dog", "fish", "squirrel"
function End-Script {
Get-Variable psArray* | Remove-Variable -Scope Script
}
function Display-Menu {
Write-Host "This is a menu..." -ForegroundColor Green
Write-Host "Here are your options:"
Write-Host
Write-Host "`t1 - ArrayList"
Write-Host "`t2 - Array"
Write-Host "`t0 - quit (do nothing)"
Write-Host
# one of many methods for input validation is a Recursive Script Block:
$tryInput = {
try {
[ValidateSet(0, 1, 2)] $choice = Read-Host "Choose 1-2 (or 0 to quit)"
$choice
}
catch {
Write-Warning 'Invalid choice!'
& $tryInput
}
}
Process-Menu (& $tryInput)
}
function Process-Menu([int] $choice) {
switch($choice) {
1 {
Write-Host "You chose ArrayList:"
$psArrayList | Out-Host
}
2 {
Write-Host "You chose Array:"
$psArray | Out-Host
}
0 {
Write-Host "You chose to quit. Exiting."
End-Script
Return # => Exit this function
}
}
$tryInput = {
try {
[ValidateSet('y', 'n')] $choice = Read-Host "Return to main menu? (y/n)"
$choice
}
catch {
Write-Warning 'Invalid choice!'
& $tryInput
}
}
# No need to check for `N`
if((& $tryInput) -eq 'y') { Display-Menu }
}
Display-Menu

Powershell - Searching value for 32 and 64 bits in registry

I currently working on powershell script who collect some datas into registry.
To perform these action, I use a similar code:
$Ifkeyexist = Test-Path 'HKLM:\SOFTWARE\WOW6432Node\XXXX\YYY\ZZZ\environment\'
if ($Ifkeyexist -eq "True")
{
$GetProductHotfix = Get-ItemPropertyValue 'HKLM:\SOFTWARE\WOW6432Node\XXXX\YYY\ZZZ\environment\' 'ProductHotfix'
Write-host "- Product Hotfix: $GetProductHotfix"
}
else {
write-host "- Unable to find product hotfix" -ForegroundColor red
}
}
Question:
in the example above, is it possible to find the value "ProductHotfix" in the 32 and 64 bit registry path?
Thanks by advance for your advices :)
Regards,
LEFBE
I would do something like below:
foreach ($path in 'HKLM:\SOFTWARE\XXXX\YYY\ZZZ\environment', 'HKLM:\SOFTWARE\WOW6432Node\XXXX\YYY\ZZZ\environment') {
$hotfix = Get-ItemPropertyValue -Path $path -Name 'ProductHotfix' -ErrorAction SilentlyContinue
# assuming you want to exit the loop at the first successfull 'hit'
if ($hotfix) { break }
}
if ($hotfix) {
Write-Host "- Product Hotfix: $hotfix"
}
else {
Write-Host "- Unable to find product hotfix" -ForegroundColor Red
}

How to count the process using PowerShell?

I would like to count how many times that I check the result.
This the part of the process looks like:
function GetValueResult
{
...Some Process...
$Result = $ReturnCode
}
GetValueResult
if ($Result -eq 0)
{
Write-Host "The process Pass"
Restart-Computer
}
elseif ($Result -eq 1)
{
Write-Host "Try again"
GetValueResult
#This part I need to know how many times that I call this function "GetValueResult"
}
Anyone can help me how to count how many times that I call the function "GetValueResult"?
If it already 3 times, than I need to do further action. Thanks for help.
You could add a simple loop inside your function and output an object with both the ResultCode and the number of tries:
function GetValueResult {
# initialize to error code
$ResultCode = -1
for ($numTries = 0; $numTries -lt 3; $numTries++) {
# ...Some Process...
# exit the loop if we have a correct $ResultCode
if ($ResultCode -eq 0) { break }
Write-Host "Try again"
}
# output an object with the resultcode and the number of tries
[PsCustomObject]#{
ResultCode = $ResultCode
Tries = $numTries + 1
}
}
$result = GetValueResult
if ($result.ResultCode -eq 0) {
Write-Host "The process Pass"
Restart-Computer
}
else {
Write-Host "Bad result after $($result.Tries) tries.."
}
You can use increment for this purpose.
$Result = 0
foreach (...){
$Result++
if ($Result -ge 3){
...your action...
}
}
Also, I can't find any loop in your script, so how would you count in this case? Please share more details about what are you trying to achieve with it, perhaps you need to redesign it from the beginning.