Using PowerShell to add an extension to files - powershell

I have a directory of files that I'd like to append file extension to as long as they don't have an existing, specified extension. So add .txt to all file names that don't end in .xyz. PowerShell seems like a good candidate for this, but I don't know anything about it. How would I go about it?

Here is the Powershell way:
gci -ex "*.xyz" | ?{!$_.PsIsContainer} | ren -new {$_.name + ".txt"}
Or to make it a little more verbose and easier to understand:
Get-ChildItem -exclude "*.xyz"
| WHere-Object{!$_.PsIsContainer}
| Rename-Item -newname {$_.name + ".txt"}
EDIT: There is of course nothing wrong with the DOS way either. :)
EDIT2: Powershell does support implicit (and explicit for that matter) line continuation and as Matt Hamilton's post shows it does make thing's easier to read.

+1 to EBGreen, except that (at least on XP) the "-exclude" parameter to get-childitem doesn't seem to work. The help text (gci -?) actually says "this parameter does not work properly in this cmdlet"!
So you can filter manually like this:
gci
| ?{ !$_.PSIsContainer -and !$_.Name.EndsWith(".xyz") }
| %{ ren -new ($_.Name + ".txt") }

Consider the DOS command FOR in a standard shell.
C:\Documents and Settings\Kenny>help for
Runs a specified command for each file in a set of files.
FOR %variable IN (set) DO command [command-parameters]
%variable Specifies a single letter replaceable parameter.
(set) Specifies a set of one or more files. Wildcards may be used.
command Specifies the command to carry out for each file.
command-parameters
Specifies parameters or switches for the specified command.
...
In addition, substitution of FOR variable references has been enhanced.
You can now use the following optional syntax:
%~I - expands %I removing any surrounding quotes (")
%~fI - expands %I to a fully qualified path name
%~dI - expands %I to a drive letter only
%~pI - expands %I to a path only
%~nI - expands %I to a file name only
%~xI - expands %I to a file extension only
%~sI - expanded path contains short names only
%~aI - expands %I to file attributes of file
%~tI - expands %I to date/time of file
%~zI - expands %I to size of file
%~$PATH:I - searches the directories listed in the PATH
environment variable and expands %I to the
fully qualified name of the first one found.
If the environment variable name is not
defined or the file is not found by the
search, then this modifier expands to the
empty string

Found this helpful while using PowerShell v4.
Get-ChildItem -Path "C:\temp" -Filter "*.config" -File |
Rename-Item -NewName { $PSItem.Name + ".disabled" }

Related

Powershell - Add extension to files containing dots

I have a script that addes the extension .xml to files without an extension.
Get-ChildItem "C:\TEST" -file "*." | rename-item -NewName {"{0}.xml" -f $_.fullname}
This works perfectly for a file such as:
BC Logistics SPA con Socio Duo - 2022-03-31 - FT 123456VESE
However, it does not work for a file such as:
A.B.C. Mini MAGAZZINI - 2022-02-25 - FT MM9 000000123
This is because of the dots. The directory also contains files that already have .xml as extension, as well as .pdf-files.
How can I add the extenion .xml to files without an extension but with dots in them?
Excluding .pdf and .xml files is not an option as the directory also contains other files that are deleted in the process.
The challenge is that nowadays filename extensions are a convention, and that most APIs, including .NET's, consider anything after the last ., if any, to be the extension, even if it isn't meant to be one. E.g., in A.B.C. Mini, . Mini (sic) is considered the extension, whereas -Filter *. in effect only matches names that contain no . at all.
If you're willing to assume that any file that doesn't end in . followed by 3 characters (e.g., .pdf) is an extension-less file, you can use the following:
# Note: Works with 3-character extensions only, doesn't limit what those chars.
# may be.
Get-ChildItem -File C:\TEST |
Where-Object Extension -NotLike '.???' |
Rename-Item -NewName { '{0}.xml' -f $_.FullName } -WhatIf
Note: The -WhatIf common parameter in the command above previews the operation. Remove -WhatIf once you're sure the operation will do what you want.
If you need to match what characters are considered part of an extension more specifically and want to consider a range of character counts after the . - say 1 through 4 - so that, say, .1 and .html would be considered extensions too:
# Works with 1-4 character extensions that are letters, digits, or "_"
Get-ChildItem -File C:\TEST |
Where-Object Extension -NotMatch '^\.\w{1,4}$' |
Rename-Item -NewName { '{0}.xml' -f $_.FullName } -WhatIf
Note the use of a regex with the -notmatch operator.
Regex ^\.\w{1,4}$ in essence means: match any extension that has between 1 and 4 word characters (\w), where a word characters is defined as either a letter, a digit, or an underscore (_).
See this regex101.com page for a detailed explanation and the ability to experiment.

Batch copy and rename files with PowerShell

I'm trying to use PowerShell to batch copy and rename files.
The original files are named AAA001A.jpg, AAB002A.jpg, AAB003A.jpg, etc.
I'd like to copy the files with new names, by stripping the first four characters from the filenames, and the character before the period, so that the copied files are named 01.jpg, 02.jpg, 03.jpg, etc.
I have experience with Bash scripts on Linux, but I'm stumped on how to do this with PowerShell. After a couple of hours of trial-and-error, this is as close as I've gotten:
Get-ChildItem AAB002A.jpg | foreach { copy-item $_ "$_.name.replace ("AAB","")" }
(it doesn't work)
Note:
* While perhaps slightly more complex than abelenky's answer, it (a) is more robust in that it ensures that only *.jpg files that fit the desired pattern are processed, (b) shows some advanced regex techniques, (c) provides background information and explains the problem with the OP's approach.
* This answer uses PSv3+ syntax.
Get-ChildItem *.jpg |
Where-Object Name -match '^.{4}(.+).\.(.+)$' |
Copy-Item -Destination { $Matches.1 + '.' + $Matches.2 } -WhatIf
To keep the command short, the destination directory is not explicitly controlled, so the copies will be placed in the current dir. To ensure placement in the same dir. as the input files, use
Join-Path $_.PSParentPath ($Matches.1 + '.' + $Matches.2) inside { ... }.
-WhatIf previews what files would be copied to; remove it to perform actual copying.
Get-ChildItem *.jpg outputs all *.jpg files - whether or not they fit the pattern of files to be renamed.
Where-Object Name -match '^.{4}(.*).\.(.+)$' then narrows the matches down to those that fit the pattern, using a regex (regular expression):
^...$ anchors the regular expression to ensure that it matches the whole input (^ matches the start of the input, and $ its end).
.{4} matches the first 4 characters (.), whatever they may be.
(.+) matches any nonempty sequence of characters and, due to being enclosed in (...), captures that sequence in a capture group, which is reflected in the automatic $Matches variable, accessible as $Matches.1 (due to being the first capture group).
. matches the character just before the filename extension.
\. matches a literal ., due to being escaped with \ - i.e., the start of the extension.
(.+) is the 2nd capture group that captures the filename extension (without the preceding . literal), accessible as $Matches.2.
Copy-Item -Destination { $Matches.1 + '.' + $Matches.2 } then renames each input file based on the capture-group values extracted from the input filenames.
Generally, directly piping to a cmdlet, if feasible, is always preferable to piping to the Foreach-Object cmdlet (whose built-in alias is foreach), for performance reasons.
In the Copy-Item command above, the target path is specified via a script-block argument, which is evaluated for each input path with $_ bound to the input file at hand.
Note: The above assumes that the copies should be placed in the current directory, because the script block outputs a mere filename, not a path.
To control the target path explicitly, use Join-Path inside the -Destination script block.
For instance, to ensure that the copies are always placed in the same folder as the input files - irrespective of what the current dir. is - use:
Join-Path $_.PSParentPath ($Matches.1 + '.' + $Matches.2)
As for what you've tried:
Inside "..." (double-quoted strings), you must use $(...), the subexpression operator, in order to embed expressions that should be replaced with their value.
Irrespective of that, .replace ("AAB", "") (a) breaks syntactically due to the space char. before ( (did you confuse the [string] type's .Replace() method with PowerShell's -replace operator?), (b) hard-codes the prefix to remove, (c) is limited to 3 characters, and (d) doesn't remove the character before the period.
The destination-location caveat applies as well: If your expression worked, it would only evaluate to a filename, which would place the resulting file in the current directory rather than the same directory as the input file (though that wouldn't be a problem, if you ran the command from the current dir. or if that is your actual intent).
In Powershell:
(without nasty regexs. We hates the regexs! We does!)
Get-ChildItem *.jpg | Copy-Item -Destination {($_.BaseName.Substring(4) -replace ".$")+$_.Extension} -WhatIf
Details on the expression:
$_.BaseName.Substring(4) :: Chop the first 4 letters of the filename.
-replace ".$" :: Chop the last letter.
+$_.Extension :: Append the Extension
Not Powershell, but Batch File:
(since someone wants to be ultra-pedantic about comments)
#echo off
setlocal enabledelayedexpansion
for %%a in (*.jpg) do (
::Save the Extension
set EXT=%%~xa
::Get the Source Filename (no extension)
set SRC_FILE=%%~na
::Chop the first 4 chars
set DST_FILE=!SRC_FILE:~4!
::Chop the last 1 char.
set DST_FILE=!DST_FILE:~,-1!
:: Copy the file
copy !SRC_FILE!!EXT! !DST_FILE!!EXT! )
try this:
Get-ChildItem "C:\temp\Test" -file -filter "*.jpg" | where BaseName -match '.{4,}' |
%{ Copy-Item $_.FullName (Join-Path $_.Directory ("{0}{1}" -f $_.BaseName.Substring(4, $_.BaseName.Length - 5), $_.Extension)) }

How to find whether a non-command file is available in the system path?

I want to test whether a certain file is in the system PATH. in cmd, I can do it using where.exe my.dll.
How do I do it in PowerShell?
This answer suggests Get-Command, which works only for executables - I want to find DLLs as well.
gci ($env:Path).split(';') -Filter *.dll
You could search the path for it as follows:
$ENV:Path -split ';' | % { if ( test-path "$_\my.dll") { write-host $_ } }
The PATH variable is semi-colon separated, so you can split the string using ; as the delimiter, then loop over each location with the file you're seeking appended. If a location is printed, your file will be on the path.

Copy file with square brackets [ ] in the filename and use * wildcard

I'm using PowerShell on Windows 7, and writing a script to copy a bunch of files from one folder structure to another. Kind of like compiling. The PowerShell Copy-Item cmdlet thinks that square brackets, [ ], are wildcards of some kind, and I am not able to escape them for some reason.
I can't use -LiteralPath, because I want to use an asterisk * wildcard since the filename has a date as part of the filename, and the date changes. The date is used as a version number.
This post was helpful, but no amount of ticks (2x or 4x per bracket) escapes the square brackets.
I am not receiving an error; PowerShell behaves the same as if I entered in the wrong filename.
This is the specific line I'm working on:
#to Fusion Server
Copy-item -Path $FSG\$SW\0.RoomView.Notes\starter\"[RoomView] Versions explained*.pdf" -Destination $FSG\$containerFolder\$rootFolder\"Fusion Server"\
And this is the whole thing:
# Compiles the Fusion packet for distribution
###############################
###########Variables###########
###############################
#folder structure
$FSG = "F:\FSG"
$containerFolder = "Packet.Fusion for IT and AV Professionals"
$rootFolder = "Fusion for IT and AV pros $(Get-Date -format “MM-dd-yyyy”)"
$subRoot1 = "Fusion Server"
$subRoot2 = "Scheduling Enhancement and Panels"
$subRoot2sub1 = "Scheduling Panels"
$subRoot3 = "SQL Server"
#source folders
$HW = "0.Hardware"
$3SMDoc = "0.Hardware\TPMC-3SM.Documentation"
$4SMDoc = "0.Hardware\TPMC-4SM.Documentation"
$4SMDDoc = "0.Hardware\TPMC-4SM-FD.Documentation"
$730Doc = "0.Hardware\TSW-730.Documentation"
$730OLH = "0.Hardware\TSW-730.OLH"
$CENRVS = "0.Hardware\CEN-RVS.Notes"
$ProjMgmt = "0.Project Management"
$SW = "0.Software"
$RVLicensing = "0.Software\0.RoomView.License"
$RVNotes = "0.Software\0.RoomView.Notes"
$SQLLicensing = "0.Software\database.SQL.Licensing"
$SQLNotes = "0.Software\database.SQL.Notes"
$FRVMarketing = "0.Software\Fusion RV.Marketing"
$FRVNetworking = "0.Software\Fusion RV.Networking"
$FRVNotes = "0.Software\Fusion RV.Notes"
###############################
#create the directory structure
###############################
md -Path $FSG\$containerFolder -Name $rootFolder
cd $FSG\$containerFolder\$rootFolder
md "eControl and xPanels"
md "Fusion Server" #$subRoot1
md "Getting Started as a User"
md "Project Management"
md "RoomView Connected Displays"
md "Scheduling Enhancement and Panels" #$subRoot2
md "SQL Server" #$subRoot3
cd $FSG\$containerFolder\$rootFolder\$subRoot1
md "CEN-RVS"
md "Licenseing Information"
md "Networking"
md "Official Documentation"
md "Prerequisites, including powerShell script"
md "Product Info"
md "Requirements"
md "Tech Info"
md "Windows Authentication to Fusion RV"
cd $FSG\$containerFolder\$rootFolder\$subRoot2
md "Outlook Add-in"
md "Scheduling Panels" #$subRoot2sub1
cd $FSG\$containerFolder\$rootFolder\$subRoot2\$subRoot2sub1
md "TPMC-3SM"
md "TPMC-4SM"
md "TPMC-4SM-FD"
md "TSW-730"
cd $FSG\$containerFolder\$rootFolder\$subRoot3
md "Multi-database model only"
md "SQL Licensing"
cd $FSG\$containerFolder
#reset current folder
###############################
#copy the files
###############################
#Copy-Item -Path C:\fso\20110314.log -Destination c:\fsox\mylog.log
#To the root
Copy-item -Path $FSG\$ProjMgmt\starter\"Fusion Support Group Contact info*.pdf" -Destination $FSG\$containerFolder\$rootFolder\
Copy-item -Path $FSG\$containerFolder\"Fusion for IT and AV professionals release notes.txt" -Destination $FSG\$containerFolder\$rootFolder\
#to eControl and xPanels
Copy-item -Path $FSG\$SW\xpanel.Notes\starter\*.* -Destination $FSG\$containerFolder\$rootFolder\"eControl and xPanels"\
#to Fusion Server
Copy-item -Path $FSG\$SW\0.RoomView.Notes\starter\"[RoomView] Versions explained*.pdf" -Destination $FSG\$containerFolder\$rootFolder\"Fusion Server"\
What can I do to escape the square brackets and still use a wildcard filename part of the Copy-Item cmdlet?
In this situation, you have to use double-backticks with single quotes in order to escape the brackets. You can also use quadruple backticks when you use double quoted strings.
So the fixed line of code is:
Copy-item -Path $FSG\$SW\0.RoomView.Notes\starter\'``[RoomView``] Versions explained*.pdf' -Destination $FSG\$containerFolder\$rootFolder\'Fusion Server'\
Another good resource on file paths and wired characters etc. is to read this article: Taking Things (Like File Paths) Literally
EDIT
Thanks to #mklement0 for highlighting that the true cause of this
inconsistency is because of a bug currently in
PowerShell1.
This bug causes escaping of wildcard characters, as well as backticks
with the default -Path parameter to behave differently than other
parameters e.g. the -Include and -Filter parameters.
To expand on #mklement0's excellent answer, and comments, and other answers below:
To better understand why we need single quotes and two back ticks in this situation; (and to highlight the bug and inconsistencies) let's run through some examples to demonstrate what is going on:
Get-Item, and associated cmdlets (Get-ChildItem, Copy-Item, etc.), handle the -Path parameter differently when dealing with a combination of escaped wildcard characters and unescaped wildcard characters *at the same time***!
TLDR: The underlying reason that we need a combination of single quotes and double backticks is how the underlying PowerShell provider parses the -Path parameter string for wildcards. It appears to parse it once for the escape characters, and a second time for the evaluation of the wildcard.
Let's go through some examples to demonstrate this odd outcome:
First, let's create two files to test with called File[1]a.txt and File[1]b.txt
"MyFile" | Set-Content '.\File`[1`]a.txt'
"MyFriend" | Set-Content '.\File`[1`]b.txt'
We'll try different ways to get the file. We know that Square brackets [ ] are wildcards, and so we need to escaped them with the backtick character.
We will try to get one file explicitly.
Let's start by using single quoted literal strings:
PS C:\> Get-Item 'File[1]a.txt'
PS C:\> Get-Item 'File`[1`]a.txt'
Directory: C:\
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 2019-09-06 5:42 PM 8 File[1]a.txt
PS C:\> Get-Item 'File``[1``]a.txt'
Directory: C:\
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 2019-09-06 5:42 PM 8 File[1]a.txt
For single quoted strings, one backtick is all that is required to retrieve the file, but two backticks also work.
Using Double quoted strings we get:
PS C:\> Get-Item "File[1]a.txt"
PS C:\> Get-Item "File`[1`]a.txt"
PS C:\> Get-Item "File``[1``]a.txt"
Directory: C:\
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 2019-09-06 5:42 PM 8 File[1]a.txt
For double quoted strings, as expected, we can see that we need two backticks to make it work.
Now, we want to retrieve both files and use a wildcard.
Let's start with single quotes:
PS C:\> Get-Item 'File[1]*.txt'
PS C:\> Get-Item 'File`[1`]*.txt'
PS C:\> Get-Item 'File``[1``]*.txt'
Directory: C:\
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 2019-09-06 5:42 PM 8 File[1]a.txt
-a---- 2019-09-06 5:49 PM 10 File[1]b.txt
With the single quotes, when we have a wildcard character, we need two sets of backticks. One to escape the bracket, and a second backtick to escape the backtick that we used to escape the bracket when the wildcard is evaluated.
Similarly for double quotes:
PS C:\> Get-Item "File[1]*.txt"
PS C:\> Get-Item "File`[1`]*.txt"
PS C:\> Get-Item "File``[1``]*.txt"
PS C:\> Get-Item "File```[1```]*.txt"
PS C:\> Get-Item "File````[1````]*.txt"
Directory: C:\
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 2019-09-06 5:42 PM 8 File[1]a.txt
-a---- 2019-09-06 5:49 PM 10 File[1]b.txt
With double quotes it's a little more verbose to evaluate with a wildcard. In this case, we need four sets of back ticks. For double quotes we need two backticks to escape the bracket, and another two backticks to escape the escape characters once it comes to evaluation of the star wildcard.
EDIT
As #mklement0 mentions, this behavior with the -Path parameter is inconsistent, and behaves differently than the -Include parameter, where only a single backtick is required to properly escape the brackets. This may be "fixed" in a later version of PowerShell.
1 As of Windows PowerShell v5.1 / PowerShell Core 6.2.0-preview.3
An overview and some background information:
In order to effectively escape a character that you want to be interpreted verbatim as part of a wildcard expression, it must be `-escaped as seen by the target cmdlet (its underlying PowerShell drive provider).
Ensuring that can get tricky, because ` (backtick) is also used as the escape character in double-quoted strings ("...") and unquoted command arguments (which for the most part behave like double-quoted strings).
Note: The scenario in the question doesn't allow use of -LiteralPath, but in cases where you know a path to be a concrete, literal path, use of the -LiteralPath (which can be shorted to -lp in PowerShell Core) is the best choice - see this answer.
When passing an argument to the wildcard-supporting -Path parameter of a PowerShell drive provider-related cmdlet (Get-ChildItem, Copy-Item, Get-Content, ...) and you want [ and ] to be treated verbatim rather than as a character set/range expression:
String-literal representations:
'file`[1`].txt'
` chars. are preserved as-is inside '...', so the target cmdlet sees them, as intended.
"file``[1``].txt"
``, i.e. doubling is needed inside "..." in order to preserve a single ` in the resulting string (the first ` is the (double-quoted) string-internal escape character, and the second ` is the character it escapes, to be passed through).
file``[1``].txt
Ditto for unquoted command arguments, which (for the most part) act like "..."
Caveat: Due to a bug - see this GitHub issue - mixing (unescaped) ? or * with escaped [ and ] requires the latter to be doubly escaped (with ``, as seen by the target cmdlet / provider):
If you wanted to match literal filename file[1].txt with a wildcard pattern that matches [ and ] literally while also containing special character * (to match any run of characters), instead of the expected 'file`[1`]*', you'll have to use 'file``[1``]*' (sic); with a double-quoted or unescaped argument you then have to effectively use quadruple backticks: "file````[1````]*" / file````[1````]* - see this answer for more.
Note that direct use of wildcards with the -like operator is not affected:
'a[b' -like 'a`[*' is - correctly - $true,
whereas 'a[b' -like 'a``[*' - rightfully - complains about an invalid pattern.
Similarly, parameters -Include and -Exclude are not affected.
-Filter plays by different rules to begin with: [...] as a construct isn't supported at all, and [ and ] chars. are always considered literals (again, see this answer).
To escape a path string programmatically, via a variable, use:
$literalName = 'file[1].txt'
$escapedName = [WildcardPattern]::Escape($literalName) # -> 'file`[1`].txt'
I use this:
Copy-Item $file.fullname.replace("[", "``[").replace("]", "``]") $DestDir
The way that Powershell automatically tab-completes the filename is usually the best way,
Example:
copy-item '.\file`[test`].txt'
On PowerShell v 2.0 and up the escape character to use is the backslash. For example, if we want to remove the brackets from this string "[Servername: QA01]" which is the sort of output we get from the Exchange Admin PowerShell cmdlet activity in System Center Orchestrator, we use the following logic:
$string -replace '\[','' -replace '\]',''
>Servername: QA01
This is pretty weird. See, you have to use a single-quote (which normally implies in PowerShell 'evaluate this precisely as written', so this is very odd syntax).
Don't feel bad for not figuring this out on your own, this is very odd syntax.
Apparently, square brackets need double-backticks to escape, which is unusual. Reference here.
You're sure that doesn't work? I've seen it referred to a few times.
Edit: Yes, it works, you used double quotes instead of backticks.
Double quote is above the apostrophe character, next to the Enter key. Backtick is right underneath the Escape key, sharing the key with the tilde, ~.
One option is to get the filenames using the legacy dir, which will let you use the * wildcard character, but doesn't try to "blob" the square brackets. Then feed that list to move-item using -literalpath
cmd /c dir *]* /b |
foreach { Move-Item -LiteralPath $_ -Destination <destination path> }
Assuming nothing else matches, you can use ? instead of the brackets. A file named "a[h-j]", copying to directory "foo":
copy-item a?h-j? foo
There's a difference between ' and `:
The first is the single quote that is the non-shift character on the " key.
The second is the backtick that I thought I was using but actually wasn't. It's the nonshift character on the ~ key.
This works:
# to Fusion Server
Copy-item -Path $FSG\$SW\0.RoomView.Notes\starter\'``[RoomView``] Versions explained*.pdf' -Destination $FSG\$containerFolder\$rootFolder\"Fusion Server"\

Test-Path behavior in Powershell

I'm trying to write a script in powershell to batch convert video files.
The way I intend to use it is to go to some folder full of video files and run it. It uses a conversion program that can be run in "command-line mode" (named handbrake) and saves the converted files with "-android" appended to them before the file extension. For example, if I have a file named video1.avi in the folder, after running the script the folder has 2 files: video1.avi and video1-android.avi
The reason I want to do this this way is so that I can check if, for each video file, there is a converted version of it (with -android appended to the name). And if so, skip the conversion for that file.
And this is where I'm having touble. The problem is the Test-Path's behavior (the cmdlet I'm using to test if a file exists).
What happens is, if the video file has an "unusual" name (for example in my case it's video[long].avi) Test-Path always returns False if you try to check if that file exists.
An easy way for you to test this is for example to do this:
Go to an empty folder,
run notepad to create a file with "[" in its name:
&notepad test[x].txt
Save the file
then do this:
Get-ChildItem | ForEach-Object {Test-Path $_.FullName}
It does not return true! It should right? Well it doesn't if the file has "[" in its name (I didn't check for any other special characters)
I've realized that if you escape the "[" and "]" it works
Test-Path 'test`[x`].txt'
returns true.
How can I go around this issue? I want to be able to: given a BaseName of a file, append it "-android.avi" and check if a file with that name exists.
Thanks,
Rui
Many PowerShell cmdlets have Path parameters that support wildcarding. As you have observed, in PowerShell not only is * a wildcard but [ and ] are also considered wildcard characters. You can read more about this in the help topic about_Wildcards.
For your issue, if you don't need wildcarding then I would recommend using the -LiteralPath parameter. This parameter doesn't support wildcarding and accepts [ and ] as literal path characters e.g.:
Get-ChildItem | ForEach {Test-Path -LiteralPath `
"$([io.path]::ChangeExtension($_.FullName,'avi'))"}
FYI, the reason piping the output of Get-ChildItem directly into Test-Path works is because the LiteralPath parameter has an alias "PSPath" that maps to the PSPath property on the FileInfo object output by Get-ChildItem. That property gets bound to the LiteralPath (er PSPath) parameter "by property name".
dir | % {test-path "$($_.Name)-android.avi"}