illegal characters in path using powershell - powershell

I need to verify one path using powershell. The problem is when given the path like Test-Path -Path "\\\10.2.200.13\share\Logger\Logger" its working fine, but my requirement is that, this path will be available in a Notepad - we need to read the path from the notepad then verify it. Here is the code:
$var = ( Get-Content D:\TestPathIssue\Params.txt ) -split '='
$source1=$var[1].Trim();
test-path -Path $source1;
I am able to get path in $source1 but I don't understand why its failing in Test-Path in this approach.

Fixed by trying this-
$source1=$source1 -replace '"', ""

Check if the variable $source1 is returning path in quotes eg:- "\10.2.200.13\share\Logger\Logger" instead of \10.2.200.13\share\Logger\Logger

The following powershell code will take a list of legal characters with regex and report back on any non-legal characters found in filenames. Modify the list of legal characters as desired.
$legal = "[a-zA-Z\d\.\-'_\s\(\)&,%\[\];\!\$\+#~=#]"
ForEach ($File in Get-ChildItem -Path C:\mypath -Recurse){
ForEach ($char in $File.Name.ToCharArray()){
If ($char -notmatch $legal){
$output = $char+" found in "+$file.fullname
write-output $output
break
}
}
}

Related

How can I tell if a specified folder is in my PATH using PowerShell?

How can I tell if a specified folder is in my PATH using PowerShell?
A function like this would be great:
function FolderIsInPATH($Path_to_directory) {
# If the directory is in PATH, return true, otherwise false
}
Going off this question, you don't need a function for this but can retrieve this with $Env:Path:
$Env:Path -split ";" -contains $directory
The -contains operator is case-insensitive which is a bonus. It could be useful placing this in a function to ensure trailing slashes are trimmed, but that's uncommon:
function inPath($directory) {
return ($Env:Path -split ';').TrimEnd('\') -contains $directory.TrimEnd('\')
}
There's a bunch of answers that do a $path.Split(";") or $path -split ";" that will probably be fine for 99.9% of real-world scenarios, but there's a comment on the accepted answer on a similar question here by Joey that says:
Will fail with quoted paths that contain semicolons.
Basically, it's a bit of an edge case, but this is a perfectly valid PATH on Windows:
c:\temp;"c:\my ; path";c:\windows
so here's a hot mess of code to address that...
function Test-IsInPath
{
param( [string] $Path, [string] $Folder )
# we're going to treat the path as a csv record, but we
# need to know how many columns there are so we can create
# some fake header names. this might give a higher count
# than the real value if there *are* quoted folders with
# semicolons in them, but that's not really an issue
$columnCount = $Path.Length - $Path.Replace(";","").Length
# generate the list of column names. the actual names
# don't matter - it's just so ConvertFrom-Csv treats our
# PATH as a data row instead of a header row
$headers = 0..$columnCount
# parse the PATH as a csv record using ";" as a delimiter
$obj = $path | ConvertFrom-Csv -header $headers -delimiter ";"
# extract an array of all the values (i.e. folders)
# in the record we just parsed
$entries = $obj.psobject.properties.value
# check if the folder we're looking for is in the list
return $entries.Contains($Folder)
}
Whether this is a "better" answer than the simple split approach depends on whether you expect to have quoted folders that contain semicolons in your PATH or not :-)...
Example usage:
PS C:\> Test-IsInPath -Path $env:PATH -Folder "c:\temp"
False
PS C:\> Test-IsInPath -Path "c:\temp;`"c:\my ; path`";c:\windows" -Folder "c:\temp"
True
PS C:\> Test-IsInPath -Path "c:\temp;`"c:\my ; path`";c:\windows" -Folder "c:\my ; path"
True
Note: what this still doesn't solve is paths that end (or don't end) with a trailing "\" - e.g. testing for C:\temp when the PATH contains C:\temp\ and vice versa.
I would go for something like this
function FolderIsInPATH {
param (
[parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]$your_searched_folder
[parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]$Path
)
$Folders = Get-Childitem -Path $Path -Directory
foreach ($Folder in $Folders) {
if ($Folder.Name -eq $your_searched_folder) {
##Folder found
} else {
##folder not found
}
}
}
You can get your PATH using [Environment]::GetEnvironmentVariables()
[Environment]::GetEnvironmentVariables()
Or if you want to get the user environment variables:
[Environment]::GetEnvironmentVariables("User")
Next, get the PATH variable:
$Path = [Environment]::GetEnvironmentVariables().Path # returns the PATH
Then check if the specified folder is in your PATH:
$Path.Contains($Path_to_directory + ";")
The function put together:
function FolderIsInPath($Path_to_directory) {
return [Environment]::GetEnvironmentVariables("User").Path.Contains($Path_to_directory + ";")
}
However, this function is case-sensitive. You can use String.ToLower() to make it not case-sensitive.
function FolderIsInPath($Path_to_directory) {
return [Environment]::GetEnvironmentVariables("User").Path.ToLower().Contains($Path_to_directory.ToLower() + ";")
}
Now call your function like this:
FolderIsInPath("C:\\path\\to\\directory")
Note that the path must be absolute.
As pointed out in mclayton's comment, this function won't work for the last path variable. To address this issue, simply add a ; to the end of the path. Your function would now look like this.
function FolderIsInPath($Path_to_directory) {
return [Environment]::GetEnvironmentVariables("User").Path.ToLower() + ";".Contains($Path_to_directory.ToLower() + ";")
}

Commandline.todirectory? System.Diagnostics.Commandline Object to string? variable?

After Get-Proccess, I am unsure how I may extrapolate a part of the data and use that data in a command.
(Get-Process magic)[0].CommandLine
Returns
PS C:\WINDOWS\System32> "\\NAS\NAS_Software\Program\Magic.exe" "\\NAS\NAS_Database\TestSubject\"
I would like to utilize the given (test subject) directory in the results as the path in the Copy-Item.
Get-ChildItem -Path "\XXXXXXXXX\" -Include *0.dcm -Recurse | Copy-Item -Destination C:\Subjects\New
As I am not a programmer, I am hoping someone can point me in the right direction before I go down the wrong rabbit hole of objects, strings, etc...
Thank you in advance.
Try the following code snippet (I use hardcoded $x):
$x = '"\\NAS\NAS_Software\Program\Magic.exe" "\\NAS\NAS_Database\TestSubject\"'
# $x = (Get-Process magic)[0].CommandLine
$arg = ($x | ConvertFrom-Csv -Delimiter ' ' -Header prog, arg).arg
$arg ### \\NAS\NAS_Database\TestSubject\
Get-ChildItem -Path "$arg" -Include *0.dcm -Recurse | Copy-Item -Destination C:\Subjects\New
In the described particular case (no spaces in paths), the following would work as well:
$arg = $x.split(' ',[StringSplitOptions]::RemoveEmptyEntries)[1].Trim('"')
However, I'd prefer the ConvertFrom-Csv cmdlet to correctly handle possible space(s) in any part of $x.
The commandline property is already a string (only powershell 7 has this). This is really a question about how to get part of a string. I would do this. -split into the first word, then use Split-Path to get the directory, and -replace the double-quote with nothing.
$commandline = '"\\NAS\NAS_Software\Program\Magic.exe" "\\NAS\NAS_Database\TestSubject\"'
(split-path (-split $commandline)[0] ) -replace '"'
\\NAS\NAS_Software\Program

How can I replace \\server\Share$ to D: using powershell

I'm trying to gather a report of long directory paths to provide to each user who has them so that they can use it and make this folders paths short.
How can I replace \\server\Share$ to X: ? I tried the below but nothing changes. I can only get results if I do only one character or one string "\\server" but not the combination "\\server\Share$" can someone tell me what I'm doing wrong.
$results= "\\\server\Share$\super\long\directory\path\"
$usershare="\\\server\Share$"
$Results | ForEach-Object { $_.FullName = $_.FullName -replace "$usershare", 'X:' }
The output I need is which is what the users will see in their systems.
X:\super\long\directory\path\
Because the $userShare variable contains characters that have special meaning in Regular Expressions (and -replace uses Regex), you need to [Regex]::Escape() that string.
First thing to notice is that you start the UNC paths with three backslashes, where you should only have two.
Next is that your $results variable is simply declared as string and should probably be the result of a Get-ChildItem command..
I guess what you want to do is something like this:
$uncPath = "\\server\Share$\super\long\directory\path\" #"# the UNC folder path
$usershare = "\\server\Share$"
$results = Get-ChildItem -Path $uncPath | ForEach-Object {
$_.FullName -replace ([regex]::Escape($usershare)), 'X:'
}
Hope that helps

Loop to replace c:\, d:\ ... z:\ with \\servername\c$\

I'm actually trying to build some code to identify rights on shared folders in every single server I've got in my enterprise.
For now, I've already listed every single server and exported it in a .txt file, did a loop on this .txt to export in an other .txt file all shared folders.
All this is working fine but the path is like : c:\...\...\folder$.
To be able to use this I need to do a loop to replace c:\ d:\ etc. with \\servername\c$\.
I've tried using [system.io.file]::ReadAllText and WriteAllText, it's working fine for one letter but didn't find a way to do a loop on it.
I've tried
get-content ... -replace "c:\","\\$ServerName\c$\" ` -replace "d:\" ...
but got an error about regular expression not valid, so trying with [regex]::Escape but didn't work as expected neither...
Powershell
$contenu = [System.IO.File]::ReadAllText("$path\$SharedFolders.txt").Replace("C:\","\\$SharedFolders\c$\")
[System.IO.File]::WriteAllText("$path\$SharedFolders.txt", $contenu)
Powershell
(Get-Content "$path\$SharedFolders.txt") | foreach {
$_ -replace "C:\","\\$SharedFolders\C$\" `
-replace "D:\","\\$SharedFolders\D$\" `
[...] | Set-Content "$path\$sharedfolders.txt"}
And i'd like to have something like that :
Powershell
('a'..'z').ForEach({ (Get-Content "$path\$SharedFolders.txt" -Raw).replace("$_`:\","\\$SharedFolders\$_$") })
But I'm too newbie in Powershell to make it work proprely
You need PSv6 to use 'a'..'z'
The -replace operator is RegEx based, you need to escape a literal backslash with another one in the pattern.
following #Lee_Daileys hint build a RegEx with valid Drive letters
$OFS = '|'
$RE = ('('+(Get-Psdrive -PSProvider filesystem).where({$_.Displayroot -notmatch '^\\'}).name)+'):\\'
$OFS = $Null
"`$RE = '{0}'" -f $RE
'Loop to replace c:\, d:\ … z:\ with \\servername\c$\' -replace $RE,"\\servername\`${1}$\"
Sample output on my PC
$RE = '(A|C|D):\\'
Loop to replace \\servername\c$\, \\servername\d$\ … z:\ with \\servername\c$\
Reading the file with the -raw parameter doesn't require a loop, but wil do all changes at once.
$OFS = '|'
$RE = ('('+(Get-Psdrive -PSProvider filesystem).where({$_.Displayroot -notmatch '^\\'}).name)+'):\\'
$OFS = $Null
$File = "$path\$SharedFolders.txt"
(Get-Content $File -raw) -replace $RE,"\\servername\`${1}$\" |
Set-Content $File
Well thanks for your help, I just manage to make it works like that :
$lecteur=[int][char]'A'
1..26 | % {
$LR=[char]$lecteur
$contenu =[System.IO.File]::ReadAllText("$path\$SharedFolders.txt").Replace("${LR}:\","\\$SharedFolders\$LR$\")
[System.IO.File]::WriteAllText("$path\$SharedFolders.txt", $contenu)
$lecteur++
}
Hope it'll help some people ;)

How to get Get-ChildItem to handle path with non-breaking space

I have the following code that works for most files. The input file (FoundLinks.csv) is a UTF-8 file with one file path per line. It is full paths of files on a particular drive that I need to process.
$inFiles = #()
$inFiles += #(Get-Content -Path "C:\Users\sw_admin\FoundLinks.csv")
foreach ($inFile in $inFiles) {
Write-Host("Processing: " + $inFile)
$objFile = Get-ChildItem -LiteralPath $inFile
New-Object PSObject -Prop #{
FullName = $objFile.FullName
ModifyTime = $objFile.LastWriteTime
}
}
But even though I've used -LiteralPath, it continues to not be able to process files that have a non-breaking space in the file name.
Processing: q:\Executive\CLC\Budget\Co  2018 Budget - TO Bob (GA Prophix).xlsx
Get-ChildItem : Cannot find path 'Q:\Executive\CLC\Budget\Co  2018 Budget - TO Bob (GA Prophix).xlsx'
because it does not exist.
At ListFilesWithModifyTime.ps1:6 char:29
+ $objFile = Get-ChildItem <<<< -LiteralPath $inFile
+ CategoryInfo : ObjectNotFound: (Q:\Executive\CL...A Prophix).xlsx:String) [Get-ChildItem], ItemNotFound
Exception
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand
I know my input file has the non-breaking space in the path because I'm able to open it in Notepad, copy the offending path, paste into Word, and turn on paragraph marks. It shows a normal space followed by a NBSP just before 2018.
Is PowerShell not reading in the NBSP? Am I passing it wrong to -LiteralPath? I'm at my wit's end. I saw this solution, but in that case they are supplying the path as a literal in the script, so I can't see how I could use that approach.
I've also tried: -Encoding UTF8 parameter on Get-Content, but no difference.
I'm not even sure how I can check $inFile in the code just to confirm if it still contains the NBSP.
Grateful for any help to get unstuck!
Confirmed that $inFile has NBSP
Thank you all! As per #TheMadTechnician, I have updated the code like this, and also reduced my input file to only the one file having a problem.
$inFiles = #()
$inFiles += #(Get-Content -Path "C:\Users\sw_admin\FoundLinks.csv" -Encoding UTF8)
foreach ($inFile in $inFiles) {
Write-Host("Processing: " + $inFile)
# list out all chars to confirm it has an NBSP
$inFile.ToCharArray()|%{"{0} -> {1}" -f $_,[int]$_}
$objFile = Get-ChildItem -LiteralPath $inFile
New-Object PSObject -Prop #{
FullName = $objFile.FullName
ModifyTime = $objFile.LastWriteTime
}
}
And so now I can confirm that $inFile in fact still contains the NBSP just as it gets passed to Get-ChildItem. Yet Get-ChildItem says the file does not exist.
More I've tried:
Same if I use Get-Item instead of Get-ChildItem
Same if I use -Path instead of -LiteralPath
Windows explorer and Excel can deal with the file successfully.
I'm on a Windows 7 machine, Powershell 2.
Thanks again for all the responses!
It's still unclear why Sandra's code didn't work: PowerShell v2+ is capable of retrieving files with paths containing non-ASCII characters; perhaps a non-NTFS filesystem with different character encoding was involved?
However, the following workaround turned out to be effective:
$objFile = Get-ChildItem -Path ($inFile -replace ([char] 0xa0), '?')
The idea is to replace the non-breaking space char. (Unicode U+00A0; hex. 0xa) in the input file path with wildcard character ?, which represents any single char.
For Get-ChildItem to perform wildcard matching, -Path rather than -LiteralPath must be used (note that -Path is actually the default if you pass a path argument positionally, as the first argument).
Hypothetically, the wildcard-based paths could match multiple files; if that were the case, the individual matches would have to be examined to identify the specific match that has a non-breaking space in the position of the ?.
Get-ChildItem is for listing children so you would be giving it a directory, but it seems you are giving it a file, so when it says it cannot find the path, it's because it can't find a directory with that name.
Instead, you would want to use Get-Item -LiteralPath to get each individual item (this would be the same items you would get if you ran Get-ChildItem on its parent.
I think swapping in Get-Item would make your code work as is.
After testing, I think the above is in fact false, so sorry for that, but I will leave the below in case it's helpful, even though it may not solve your immediate problem.
But let's take a look at how it can be simplified with the pipeline.
First, you're starting with an empty array, then calling a command (Get-Content) which likely already returns an array, wrapping that in an array, then concatenating it to the empty one.
You could just do:
$inFiles = Get-Content -Path "C:\Users\sw_admin\FoundLinks.csv"
Yes, there is a chance that $inFiles will contain only a single item and not an array at all.
But the nice thing is that foreach won't mind one bit!
You can do something like this and it just works:
foreach ($string in "a literal single string") {
Write-Host $string
}
But Get-Item (and Get-ChildItem for that matter) accept pipeline input, so they accept multiple items.
That means you could do this:
$inFiles = Get-Content -Path "C:\Users\sw_admin\FoundLinks.csv" | Get-Item
foreach ($inFile in $inFiles) {
Write-Host("Processing: " + $inFile)
New-Object PSObject -Prop #{
FullName = $inFile.FullName
ModifyTime = $inFile.LastWriteTime
}
}
But even more than that, there is a pipeline-aware cmdlet for processing items, called ForEach-Object, to which you pass a [ScriptBlock], in which $_ represents the current item, so we could do it like this:
Get-Content -Path "C:\Users\sw_admin\FoundLinks.csv" |
Get-Item |
ForEach-Object -Process {
Write-Host("Processing: " + $_)
New-Object PSObject -Prop #{
FullName = $_.FullName
ModifyTime = $_.LastWriteTime
}
}
All in one pipeline!
But further, you're creating a new object with the 2 properties you want.
PowerShell has a nifty cmdlet called Select-Object which takes an input object and returns a new object containing only the properties you want; this would make for a cleaner syntax:
Get-Content -Path "C:\Users\sw_admin\FoundLinks.csv" |
Get-Item |
Select-Object -Property FullName,LastWriteTime
This is the power of the the pipeline passing real objects from one command to another.
I realize this last example does not write the processing message to the screen, however you could re-add that in if you wanted:
Get-Content -Path "C:\Users\sw_admin\FoundLinks.csv" |
Get-Item |
ForEach-Object -Process {
Write-Host("Processing: " + $_)
$_ | Select-Object -Property FullName,LastWriteTime
}
But you might also consider that many cmdlets support verbose output and try to just add -Verbose to some of your existing cmdlets. Sadly, it won't really help in this case.
One final note, when you pass items to the filesystem cmdlets via pipeline, the parameter they bind to is in fact -LiteralPath, not -Path, so your special characters are still safe.
I just run into the same issue. Looks like get-childitem ak gci expects the path in unicode (UTF-16). So either convert the csv file into unicode or convert the lines that include the path as unicode within your script.
Testet on PS 5.1.22621.608