Benefits of using Join-Path over string concatenation - string

What is the benefit of using Join-Path to create a file path instead of just doing something like the following?
$Folder\$FileName

Join-Path benefits:
Uses the path-separator defined for the provider on which it's running
Supports more than just filesystems (Certificates, registry, etc)
Accepts multiple items to join.
Accepts credentials
Can resolve the result to a full path if it's relative
Accepts arguments from the pipeline without a Foreach-Object intermediary

Related

Mass Conversion of (macintosh) .csv to (ms-dos) .csv

I am using a program to export hundreds of rows in an Excel sheet into separate documents, but the problem is that a PLC will be reading the files and they only save in (macintosh).csv with no option for windows. Is there a way to bulk convert multiple files with different names into the correct format?
I have used this code for a single file but I do not have the knowledge to use it for multiple in a directory
$path = 'c:\filename.csv';
[System.IO.File]::WriteAllText($path.Remove($path.Length-3)+'txt',[System.IO.File]::ReadAllText($path).Replace("`n","`r`n"));
Thank you
The general PowerShell idiom for processing multiple files one by one:
Use Get-ChildItem (or Get-Item) to enumerate the files of interest, as System.IO.FileInfo instances.
Pipe the result to a ForEach-Object call, whose script-block argument ({ ... }) is invoked once for each input object received via the pipeline, reflected in the automatic $_ variable.
Specifically, since you're calling .NET API methods, be sure to pass full, file-system-native file paths to them, because .NET's working directory usually differs from PowerShell's. $_.FullName does that.
Therefore:
Get-ChildItem -LiteralPath C:\ -Filter *.csv |
ForEach-Object {
[IO.File]::WriteAllText(
[IO.Path]::ChangeExtension($_.FullName, 'txt'),
[IO.File]::ReadAllText($_.FullName).Replace("`n", "`r`n")
)
}
Note:
In PowerShell type literals such as [System.IO.File], the System. part is optional and can be omitted, as shown above.
[System.IO.Path]::ChangeExtension(), as used above, is a more robust way to obtain a copy of a path with the original file-name extension changed to a given one.
While Get-ChildItem -Path C:\*.csv or even Get-ChildItem C:\*.csv would work too (Get-ChildItem's first positional parameter is -Path), -Filter, as shown above, is usually preferable for performance reasons.
Caveat: While -Filter is typically sufficient, it does not use PowerShell's wildcard language, but delegates matching to the host platform's file-system APIs. This means that range or character-set expressions such as [0-9] and [fg] are not supported, and, on Windows, several legacy quirks affect the matching behavior - see this answer for more information.

String Length different when using ISE or Powershell.exe

I have written a small user Interface with PowerShell in order to create checksums comfortable. At the moment I see a difference between using the ISE and the powershell itself.
When running the PowerShell script within the ISE I get perfect results.
This is the code I am using (Just a snippet):
$aaa = (Get-FileHash -Algorithm SHA512 -Path $str_filepath |
Select-Object -Property hash |
Format-Table -HideTableHeaders |
Out-string).TrimEnd().TrimStart()
So I create a checksum (SHA512) from a file. These are the results for one file as example:
Running the script in ISE:
0518E6DF62AB7B8D7A238039262C7A0E9F1F457D514EDE2BB8B3F4719340EF4B61053EC85ED30D07688B447DBC756F3A7455D7E0C84C7BCF62A8884E4715C8A0
Running the script in PowerShell:
0518E6DF62AB7B8D7A238039262C7A0E9F1F457D514EDE2BB8B3F4719340EF4B61053EC85ED30D07688B447DBC756F3A7455D7E0C84C7BCF62A8...
As you can see the string is shortend when using PowerShell. More confusing is that the shortening is not consistent. At home on my Windows 7 machine the string is even shorter then on my Windows 8.1 System at work. I know that there are some differences between ISE and PowerShell when running scripts regarding to styles. But shorter strings... Hmm.
So now the question. Does anyone of you have expierenced that difference between ISE and Powershell regarding to String length limitations? And if so. Does have anyone an answer for me how I can script it that there will be no different string results?
Do not use Format-* cmdlets if you need to process your data further. Those cmdlets are only for displaying data to a user. Instead expand the Hash property of the object Get-FileHash returns, either like this:
$str_checksum_sha512 = (Get-FileHash -Algorithm SHA512 -Path $str_filepath).Hash
or like this:
$str_checksum_sha512 = Get-FileHash -Algorithm SHA512 -Path $str_filepath |
Select-Object -Expand Hash

Find and replace a specific string within a specific file type located in wildcard path

Problem:
Update a specific string within numerous configuration files that are found within the subfolders of a partial path using PowerShell.
Expanded Details:
I have multiple configuration files that need a specific string to be updated; however, I do not know the name of these files and must begin my search from a partial path. I must scan each file for the specific string. Then I must replace the old string with the new string, but I must make sure it saves the file with its original name and in the same location it was found. I must also be able to display the results of the script (number of files affected and their names/path). Lastly, this must all be done in PowerShell.
So far I have come up with the following on my own:
$old = "string1"
$new = "string2"
$configs = Get-ChildItem -Path C:\*\foldername\*.config -Recurse
$configs | %{(Get-Content $_) -Replace $old, $new | Set-Content $_FullName
When I run this, something seems to happen.
If the files are open, they will tell me that they were modified by another program.
However, nothing seems to have changed.
I have attempted various modifications of the below code as well. To my dismay, it only seems to be opening and saving each file rather than actually making the change I want to happen.
$configFiles = GCI -Path C:\*\Somefolder\*.config -Recurse
foreach ($config in $configFiles) {
(GC $config.PSPath) | ForEach-Object {
$_ -Replace "oldString", "newString"
} | Set-Content $config.PSPath)
}
To further exasperate the issue, all of my attempts to perform a simple search against the specified string seems to be posing me issues as well.
Discussing with several others, and based on what have learned via SO... the following code SHOULD return results:
GCI -Path C:\*\Somefolder\*.config -Recurse |
Select-String -Pattern "string" |
Select Name
However, nothing seems to happen. I do not know if I am missing something or if the code itself is wrong...
Some questions I have researched and tried that are similar can be found at the below links:
UPDATE:
It is possible that I am being thwarted by special characters such as
+ and /. For example, my string might be: "s+r/ng"
I have applied the escape character that PowerShell says to use, but it seems this is not helping either.
Replacing a text at specified line number of a file using powershell
Find and replacing strings in multiple files
PowerShell Script to Find and Replace for all Files with a Specific Extension
Powershell to replace text in multiple files stored in many folders
I will continue my research and continue making modifications. I'll be sure to notate anything that get's me to my goal or even a step closer. Thank you all in advance.

Powershell concatenate an Environment variable with path

So I have this code:
$userprofile=Get-ChildItem Env:USERPROFILE
$localpath="$userprofile\some\path"
I would expect output of the below from $localpath:
c:\users\username\some\path
However what I get is:
System.Collections.DictionaryEntry\some\path
So, of course, something like cd $localpath fails. How would I accomplish what I need?
A convenient way to obtain the string value rather than the dictionary entry (which is technically what Get-ChildItem is accessing) is to just use the variable syntax: $Env:USERPROFILE rather than Get-ChildItem Env:USERPROFILE.
$localpath = "$env:USERPROFILE\some\path"
For more information:
PowerShell Environment Provider
about_Environment_Variables
Also, the Join-Path cmdlet is a good way to combine two parts of a path.
$localpath = Join-Path $env:USERPROFILE 'some\path'

Replacing string but duplicate part of string

I have several batch files i need to alter.
looping through the files and replacing works fine.
I just cant figure out how to have a single line like
net use w: \\someserver\someshare
replaced by two lines
net use w: /delete /yes
net use w: \\someotherserver\someshare
is this at all possible with replace and regular expressions?
Or do i have to store the driveletter in a variable to accomplish this?
thanks,
Yes, that is possible with -replace:
$yourFilePath = 'PATH_TO_YOUR_FILE'
$content = Get-Content $yourFilePath
$content -replace '^net use (\w): .*', "net use `$1: /delete /yes `n`$0" | Set-Content $yourFilePath
The script adds the desired line to your file and uses the particualr drive, but doesn't check, whether the line (net use drive: /delete /yes) already exist.

Resources