Trim quotes from read-host directory stored as variable - powershell

I have a small Powershell script I wrote to help rename folders of files, based off the filenames in another folder.
I have two read-host lines that catch the input from the user and store the input as the source folder and destination folder as strings. This makes life easier as I can drag and drop rather than full typing the path.
The problem is that Powershell keeps throwing errors, saying it can't find the drive "X:
This seems to be being caused by the quotes around the path, as removing them after dragging and dropping works fine.
Here is how it is captured:
$source = Read-Host "Source folder"
$destination = Read-Host "Destination folder"
[array]$a = Get-ChildItem $source
[array]$b = Get-ChildItem $destination
What is the easiest way to remove the quotes from those strings, before running the Get-ChildItem command? I have tried things like $source.replace, $_. trim and also $source -replace ('"', "")
Can't seem to get this to work.

Use single quotes, like so:
PS C:\> $foo = 'x:\"some weird\path"'
PS C:\> $foo
x:\"some weird\path"
PS C:\> $foo.Replace('"', '')
x:\some weird\path
PS C:\> $foo -replace '"', ''
x:\some weird\path

Related

Powershell script with a path with square brackets in a string for

I can't get my Powershell script to work with a path which has square brackets.
Input path is "c:\temp\yeah [thats it]"
param (
[string]$folderPath = $env:folderPath
)
$folderPath = $folderPath + "\"
Add-Content -Path $folderPath"01-playlist.m3u" -Value "a file name.mp3"
I looked at '-literalpath' and 'Convert-path' but I can't see how to implement that to my code.
Simply use -LiteralPath instead of -Path.
Add-Content -LiteralPath "D:\Test\yeah [thats it]\01-playlist.m3u" -Value "a file name.mp3"
Now the path is taken literally, so you cannot use wildcards as you would with Path.
By the way, your optional parameter looks strange.. Unless you have set an environment variable for it, there is no such thing as $env:folderPath
Also, to combine a path and a filename, there is a cmdlet called Join-Path. Using that is far better than using constructs like $folderPath + "\" where it is very easy to either forget backslashes or adding too many of them..
Instead, I would write
$file = Join-Path -Path $folderPath -ChildPath '01-playlist.m3u'
Add-Content -LiteralPath $file -Value "a file name.mp3"
You need to use backticks I believe. If you are doing this from a shell this works
"abc ````[123````].txt"
Note the number of back ticks changes to two if you are wrapping with single quotes.
See this answer: https://superuser.com/questions/212808/powershell-bug-in-copy-move-rename-when-filename-contains-square-bracket-charac#:~:text=Getting%20PowerShell%20to%20correctly%20recognize,four%20backticks%20to%20escape%20it.

Is there a way to filter file names by ~?

I am attempting to find all file names in a root directory that contain a ~ so they can be changed.
I have tried using the escape character (-filter "~" instead of -filter "~"), however when doing that it grabs nothing.
I have also tried putting the ~ in a string variable, but that also did not work, it just pulled the entire root folder again
I know there are about 200 files that have ~ in their name in the test directory, so this should grab 200 files.
[string] $rootfolder = "C:\Documents\Powershell-Test",
[string] $folder = "",
[string] $subfolder = "",
#Place Illegal Character Here
[string] $illegalCharacter = "~",
#place replacement Phrase here
[string] $replacementPhrase = "",
$files = Get-ChildItem -Path $rootfolder -Recurse -Filter *$illegalCharacter*
I use the same script I used to find other unwanted characters. When I ran this script for # and &, it grabbed all the files with the character, remo and printed them to a csv file.
When I ran the ~, it grabbed every file in the root folder.
I did not include the code to print the file because that code is not altered when changing what is being searched for.
-Filter qualifies the path parameter. This means you need wildcards if you don't know the exact string name of target directory or file. If you don't know where the ~ exists in the file names, you need to use *~* when qualifying the path. Per Matthias R. Jessen, -Filter "*~*" will not produce the desired result because *~* matches every single file with 8 or more characters in the name because PowerShell offloads filtering to Windows, and Windows applies the filter to both the real name and the 8dot3 name of the file system items.
The following will produce the desired result. Note this was tested on PowerShell v5.1.
$rootfolder = "C:\Documents\Powershell-Test"
$illegalCharacter = '~'
$files = Get-ChildItem -Path $rootfolder -Recurse |
Where-Object {$_.Name -like "*$IllegalCharacter*"}
Putting the wildcards in the path works for me. The -filter *~* matching short filenames thing doesn't happen in PS 6, so it appears to be a bug.
get-childitem -path $rootfolder\*$illegalCharacter* -recurse
It even matches the number in the short filename.
cmd /c dir /x
07/17/2019 02:19 PM 10 VERYLO~2.TXT verylongname.txt
ls . *2*
-a---- 7/17/2019 2:19 PM 10 verylongname.txt
"get-childitem -filter" seems like something to be avoided, like ">".

File path with quotation mark issue of Powershell

I was trying to write a script to test the availability of the file path. One of the process is that user have to input the file path or just drag the file into the Powershell command prompt.
In this process,
User will input the file path like C:\Program Files\7-Zip\7z.exe and the string will become the value of $filePath variable which will be used as the parameter of the Test-Path command.
But sometime, user will just drag the file into the Powershell command prompt so that the string will have a pair of quotation mark included just like the picture 1.
("C:\Program Files\7-Zip\7z.exe")
Picture 1
Then you will see when I try to test the path using Test-Path command with that $filePath variable while the value(string) of the $filePath included a pair of quotation mark, the result will always be False even though the path is existing and valid.
But when I use the same Test-Path command without using variable (I mean just copy and paste the file path into the command), it works normally.
IT'S WEIRD!
I have tried typing the file path by keyboard into the variable instead of dragging the file into Powershell command prompt. (Without Quotation mark)
Then use the same method to test the filepath (using variable for the file path). It works fine.
Picture 2
I don't get it. Aren't they the same thing?
when
$filePath = "C:\Program Files\7-Zip\7z.exe"
Below 2 commands SHOULD have the same result! WHY they are not?
Test-Path -Path $filePath
Test-Path -Path "C:\Program Files\7-Zip\7z.exe"
In case of drag and drop, it looks like if the path has no spaces it will return true . If it has a space then PowerShell places quotes around it. In that case, PowerShell is literally seeing the path as "C:\Program Files\7-Zip\7z.exe"
What you can do is use the -replace operator like this -
Test-Path -path ($filepath -replace '"', "") -PathType Leaf
OR
As suggested by #Josefz in the comments, you could also use Trim() method like -
Test-Path -path ($filepath.Trim('"')) -PathType Leaf
Not exactly an explanation to your problem, but you could use this as a workaround.
If the user types a filename that contains embedded " characters, then Test-Path will return $false. Why? File names cannot contain the " character; the " character is used by parsers to indicate that an argument in a string contains whitespace. So this will of course return $false:
$filePath = '"C:\Program Files\7-Zip\7z.exe"'
Test-Path $filePath
The embedded " characters are not part of the file name; you need to omit them for the result to be $true.
What version of powershell are you using? I get true for both commands
PS C:\Users> $filePath = "C:\Program Files\7-Zip\7z.exe"
PS C:\Users> Test-Path -Path $filePath
True
PS C:\Users> Test-Path -Path "C:\Program Files\7-Zip\7z.exe"
True
PS C:\Users> $PSVersionTable.PSVersion
Major Minor Build Revision
----- ----- ----- --------
5 1 17134 48
EDIT ----------
Got it, the problem is that Read-Host will save the string literally, with the quotes. The simple solution is to remove the quotes
PS C:\Users> $filePath = Read-Host -Prompt "enter input"
enter input: "C:\Program Files\7-Zip\7z.exe"
PS C:\Users> $filePath
"C:\Program Files\7-Zip\7z.exe"
PS C:\Users> Test-Path -Path $filePath
False
PS C:\Users> Test-Path -Path $filePath.replace("`"","")
True

Powershell : Write host to current directory/$computername

I'm trying to output a CSV in the current directory, but in a folder that matches the $ComputerName, which already exists. I'm doing this for a list of machines regularly and rather than manually put them in their folder it would be awesome to do it in the script.
Here is the current code, writing to the script directory.
#writing file to
[Environment]::CurrentDirectory = (Get-Location -PSProvider FileSystem).ProviderPath
Write-Host ("Saving CSV Files at " + [Environment]::CurrentDirectory + " Named the following.")
Write-Host $PritnersFilename
I've tried adding $ComputerName to various locations and had no luck.
Examples:
Write-Host ("Saving CSV Files at " + [Environment]::CurrentDirectory\$ComputerName + " Named the following.")
Write-Host ("Saving CSV Files at " + [Environment]::(CurrentDirectory\$ComputerName) + " Named the following.")
EDIT: $ComputerName is the variable of the target, not the local host
It would be easier if I saw the whole code. But I made up an example because I felt it would be easier to explain it likes this since I don't know where you get your variables from.
Pretty straight forward, it loops through the computers and if there isn't a folder in current folder named $computername it creates one. Then your export code comes in where it exports computer data to that folder we just created.
Key part: Using ".\" is the same thing as current folder.
cd C:\Scriptfolder\
# computer variables for example
$computers = #()
$computers += "HOST1"
$computers += "HOST2"
$computers += "HOST3"
# looping through all objects
Foreach($computer in $computers){
# creating folder named after computername if one doesn't exist
if(!(Test-Path ".\$computer")){
New-Item -ItemType Directory -Name $computer -Path ".\"
}
# output path with computername in it
$outputpath = ".\$computer\output.csv"
# your export code
$computer | Export-CSV $outputpath
}
[Environment]::CurrentDirectory\$ComputerName, due to being inside (...) and being used as an operand of the + operator, is parsed in expression mode, which causes a syntax error.
For an overview of PowerShell's parsing modes, see this answer of mine.
You need "..." (an expandable string) to perform your string concatenation, using subexpression operator $(...) to embed expression [Environment]::CurrentDirectory and embedding a reference to variable $ComputerName directly.
"$([Environment]::CurrentDirectory)\$ComputerName"
For an overview of string expansion (string interpolation) in PowerShell,
see this answer of mine.
Alternatively, you could use an expression with + as well (or even mix the two approaches):
# Enclose the whole expression in (...) if you want to use it as a command argument.
[Environment]::CurrentDirectory + '\' + $ComputerName
Note: The most robust (albeit slower) method for building filesystem paths is to use the Join-Path cmdlet:
# Enclose the whole command in (...) to use it as part of an expression.
Join-Path ([Environment]::CurrentDirectory) $ComputerName
Note the need for (...) around [Environment]::CurrentDirectory to ensure that it is recognized as an expression. Otherwise, since the command is parsed in argument mode, [Environment]::CurrentDirectory would be treated as a literal.

Spaces in filepath

Working on a simple script to pull workstation names from a .csv file then open a folder location on that workstation. I keep running into trouble on how to get PowerShell to not split the filepath. So far I have tried:
Single quotes: '\\$results\c$\direc\Desktop\Start Menu\Programs\Startup'
Regular quotation: "\\$results\c$\direc\Desktop\Start Menu\Programs\Startup"
Double quotes: ""\\$results\c$\direc\Desktop\Start Menu\Programs\Startup""
Backtick in front of the space: "\\$results\c$\direc\Desktop\Start` Menu\Programs\Startup"
8.3 name: "\\$results\c$\direc\Deskto~1\StartM~1\Progra~1\Startu~1"
Here is my code:
$inputFile = "C:\Users\$env:username\Desktop\workstations.csv"
$results = #()
Import-CSV -Path $inputFile -Header Workstations | % {
Invoke-Item -Path "\\$results\c$\JHMCIS\Desktop\Start Menu\Programs\Startup"
}
Everything works perfect until it reads the file path. It then kicks back an error that says the path does not exist.
Your string formatting is fine, the problem is that you just created an empty array named $results and then are adding that to the string when you do your invoke. change your last line to
% {Invoke-Item -Path "\\$($_.Workstations)\c$\JHMCIS\Desktop\Start Menu\Programs\Startup"}
Note that the above assumes that the file has no headings and only a single column that you are defining the name of using the -header param on your Import-CSV