Powershell preserve byte order mark with Set-Content (search/replace script) - powershell-4.0

I was using a Powershell script I found to help me rename a BizTalk application. The maps are stored in .btm files, and must have an XML byte order mark.
After running this script:
$configFiles = Get-ChildItem -Path "C:\MyCodePath" *.btm* -rec
foreach ($file in $configFiles)
{
(Get-Content $file.PSPath) |
Foreach-Object { $_ -replace "oldstring", "newstring" } |
Set-Content $file.PSPath
}
then I got build error:
error btm1023: Exception Caught: There is no Unicode byte order mark. Cannot switch to Unicode.

Related

Remove double quotation marks in the middle of the string field in a CSV file by using power shell

I am trying to remove the double quotation marks in the middle of the string field in a CSV file by using a power shell. Please find the attached sample data. Here is the code I am trying but it is not working. please suggest the best solution. thanks in advance.
Get-ChildItem $Outgoing -Filter *.csv | ForEach-Object {
(Get-Content $_.FullName -Raw) | Foreach-Object {
$_ -replace '(?m)(?<=,|^)"([^,"]*)"([^,"]*)"(?=,|$)', '"$1$2"'
} | Set-Content $_.FullName
}

process multiple CSV file and delete rows in a single column which has double semi colon characters using powershell

consider I have a below CSV file.
input:
ID;ITEM_ID;STATUS;
001;;RELEASED;
002;36530;RELEASED;
003;86246;RELEASED;
004;;RELEASED;
I want to remove the row that has ;; (ITEM_ID) missing and save it.I tried doing it on one sample file and it worked as expected.
Import-Csv -Path ".\TestFile.CSV" | where {$_.ITEM_ID -ne ""} | Export-Csv -Path ".\TestFile-temp.CSV" -NoTypeInformation
Remove-Item -Path '.\TestDir\TestFile.csv'
Rename-Item -Path '.\TestDir\TestFile-temp.csv' -NewName 'TestFile.csv'
output:
ID;ITEM_ID;STATUS;
002;36530;RELEASED;
003;86246;RELEASED;
The challenge is, i have multiple csv files and it doesn't has value in different columns, but in single column when i opened in excel file.
so it's not taking the condition < where {$_.ITEM_ID -ne ""} >.
Now i have to search/parse each row of each csv file, search special character (;;) in that row and delete the line and save the file.
i am good at shell scripting but, i am very new to powershell scripting. can anybody please help me to get the logic here or use other cmdlet that can do the job?
$fileDirectory = "C:\Users\Administrator\Documents\check";
foreach($file in Get-ChildItem $fileDirectory)
{
$csvFileToCheck = Import-Csv -Path $fileDirectory\$file
$noDoubleSemiComma = foreach($line in $csvFileToCheck)
{
if(Select-String << i want the logic here>>)
{
$line
}
}
$noDoubleSemiComma | Export-Csv -Path $fileDirectory\tmp.csv -NoTypeInformation
Remove-Item -Path $fileDirectory\$file
Rename-Item -Path $fileDirectory\tmp.csv -NewName $file
}
As commented, you need to add parameter -Delimiter ';' to the cmdlet otherwise a comma is used to parse the fields in the CSV.
As I understand, you also want to remove the quotes Export-Csv outputs around all fields and headers and for PowerShell version 7 you have the option to use parameter -UseQuotes AsNeeded.
As this is not available for version 5.1, I made a function ConvertTo-CsvNoQuotes some time ago to remove the quotes in a safe way. (simply replacing them all with an empty string is dangerous, because sometimes values do need quotes)
Copy that function into your script at the top, then below that, your code could be simplified like this:
$fileDirectory = "C:\Users\Administrator\Documents\check"
Get-ChildItem -Path $fileDirectory -Filter '*.csv' -File | ForEach-Object {
# for better readability store the full path of the file in a variable
$filePath = $_.FullName
(Import-Csv -Path $filePath -Delimiter ';') | ConvertTo-CsvNoQuotes -Delimiter ';' | Set-Content $filePath -Force
Write-Host "File '$filePath' modified"
}
After all helpful suggestion, i finally nailed it down. AS my power-shell version was 5.1 , i had to use logic for trimming double quotes after export-csv. Powershell version 7 and later has -UseQuotes that could have solve that too.
Hope this help others.
$fileDirectory = "C:\Users\Administrator\Documents\check";
foreach($file in Get-ChildItem $fileDirectory)
{
Import-Csv -Path $fileDirectory\$file -Delimiter ';' | where {$_..ITEM_ID -ne ""} | Export-Csv -Path $fileDirectory\temp.csv -Delimiter ';' -NoTypeInformation
$Test = Get-Content $fileDirectory\temp.csv
$Test.Replace('";"',";").TrimStart('"').TrimEnd('"') | Out-File $fileDirectory\temp.csv -Force -Confirm:$false
Remove-Item -Path $fileDirectory\$file
Rename-Item -Path $fileDirectory\temp.csv -NewName $file
Write-Output "$file file modified."
}
Any suggestion to trim down number of lines of code is welcomed.

dos2unix format conversion error while execution through TeamCity

While trying to transfer file from Windows to Unix Azure environment, I am getting error dos2unix format error
dos2unix -o /xyz/home/ABC_efg.txt failed to execute dos2unix format change.
I tried to run a PS script to fix it but does seem to work .
Get-ChildItem -File -Recurse *.txt | % { $x = get-content -raw -path $_.fullname; $x -replace "`r`n","`n" | set-content -NoNewline -path $_.fullname }
Instead of using -replace, I would prefer to read the content(s) as string array and join these strings with "`n".
Something like this:
$files = Get-ChildItem -File -Recurse -Filter '*.txt' | Select-Object -ExpandProperty FullName
$files | ForEach-Object {
(Get-Content -Path $_) -join "`n" | Set-Content -Path $_ -NoNewline -WhatIf
}
Remove the -WhatIf switch if you are satisfied with the outout shown in the console.
Well, part of the issue is that you are piping a string to Set-Content and then trying to use that string to determine where to save the file. Try changing the last part from:
$x -replace "`r`n","`n" | set-content -NoNewline -path $_.fullname
to this:
set-content -NoNewline -path $_.fullname -value ($x -replace "`r`n","`n")
If that doesn't update the formatting like you expect it to you may need to use the -Encoding parameter for Set-Content. I'm not real familiar with encoding though, so I am not sure about that.

Select directory from a file

I need my program to give me every folder containing files which are out of the Windows' number of characters limit. It means if a file has more than 260 characters (248 for folders), I need it to write the address of the file's parent. And I need it to write it only once. For now, I'm using this code:
$maxLength = 248
Get-ChildItem $newPath -Recurse |
Where-Object { ($_.FullName.Length -gt $maxLength) } |
Select-Object -ExpandProperty FullName |
Split-Path $_.FullName
But the Split-Path won't work (this is the first time I use it). It tells me the -Path parameter has a null value (I can write -Path but it doesn't change anything).
If you want an example of what I need: imagine folder3 has a 230-character address and file.txt has a 280-character address:
C:\users\folder1\folder2\folder3\file.txt
Would write:
C:\users\folder1\folder2\folder3
I'm using PS2, by the way.
Spoiler: the tool you are building may not be able to report paths over the limit since Get-ChildItem cannot access them. You can try nevertheless, and also find other solutions in the links at the bottom.
Issue in your code: $_ only works in specific contexts, for example a ForEach-Object loop.
But here, at the end of the pipeline, you're only left with a string containing the full path (not the complete file object any more), so directly passing it to Split-Path should work:
$maxLength = 248
Get-ChildItem $newPath -Recurse |
Where-Object { ($_.FullName.Length -gt $maxLength) } |
Select-Object -ExpandProperty FullName |
Split-Path
as "C:\Windows\System32\regedt32.exe" | Split-Path would output C:\Windows\System32
Sidenote: what do (Get-Item C:\Windows\System32\regedt32.exe).DirectoryName and (Get-Item C:\Windows\System32\regedt32.exe).Directory.FullName output on your computer ? These both show the directory on my system.
Adapted code example:
$maxLength = 248
Get-ChildItem $newPath -Recurse |
Where-Object { ($_.FullName.Length -gt $maxLength) } |
ForEach-Object { $_.Directory.FullName } |
Select-Object -Unique
Additional information about MAX_PATH:
How do I find files with a path length greater than 260 characters in Windows?
Why does the 260 character path length limit exist in Windows?
http://www.powershellmagazine.com/2012/07/24/jaap-brassers-favorite-powershell-tips-and-tricks/
https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx
https://gallery.technet.microsoft.com/scriptcenter/Get-ChildItemV2-to-list-29291aae
you cannot use get-childitem to list paths greater than the windows character limit.
There are a couple of alternatives for you. Try an external library like 'Alphafs' or you can use robocopy. Boe Prox has a script that utilizes robocopy and it is available on technet but i am not sure if it will work on PSV2. Anyway you can give it a try.
I've had a similar problem and resolved it like this:
$PathTooLong = #()
Get-ChildItem -LiteralPath $Path -Recurse -ErrorVariable +e -ErrorAction SilentlyContinue
$e | where {$_.Exception -like 'System.IO.PathTooLongException*'} | ForEach-Object {
$PathTooLong += $_.TargetObject
$Global:Error.Remove($_)
}
$PathTooLong
On every path that is too long, or that the PowerShell engine can't handle, Get-ChildItem will throw an error. This error is saved in the ErrorVariable called e in the example above.
When all errors are collected in $e you can filter out the ones you need by checking the error Exception for the string System.IO.PathTooLongException.
Hope it helps you out.

Powershell v2 prompting for value in foreach

This code runs in PowerShell v1 but not in PowerShell v2. It now prompts for a value:
Get-ChildItem -Path $source -Filter "*.journal" |
Where-Object { $_.Name -match 'SoundPC\[\d{1,12}-\d{1,12}\].journal' } | Sort-Object -Property CreationTime | ForEach-Object
{
$sourcefile = $_.Name
}
Can someone help?
The opening brace must be on the same line as the foreach command, currently its on a new line:
Foreach-Object {...
As Shay Levy pointed out, the brace must be on the same line as the ForEach-Object command.
... | ForEach-Object {
$sourcefile = $_.Name
}
Alternatively, you can use the backtick character ` at the end of the line to cause a continuation, which will then allow you to put the opening brace on the next line. Being a C# developer, I prefer this so that my braces can line up.
... | ForEach-Object `
{
$sourcefile = $_.Name
}

Resources