I'm trying to create a Powershell script that looks for just files with the extension .dgn within a specific directory. Then if it has a character string of "_ch_" in the name of the file it will delete it. Else it will move the file to a new directory.
Function Remove-ExtraneousCADFiles {
[CmdletBinding()]
Param (
[Parameter(ValueFromPipeline = $true)]
$paths
)
Begin {Clear-Host}
Process {
$char = "_ch_"
$fileName = Split-Path $input -leaf
$destDir = "D:\CRASH\ACCID - Lite Test\"
Write-Output ("fileName= " + $fileName)
Write-Output ("char= " + $char)
Write-Output ("_.Name= " + $_.Name)
#if ($_.contains($char)) {
#if (Where $_.Name -Match $char) {
#if ($_.Name -Match $char) {
if ($_.Name -Like $char) {
Remove-Item $_ -Force -Confirm -WhatIf
Write-Output ("Delete= " + $fileName.Name)
}
else {
#Write-Output ("Move _.FullName= " + $_.FullName)
#Write-Output ("destDir= " + $destDir)
#Write-Output ("_.BaseName= " + $_.BaseName)
#Write-Output ("_.Extension= " + $_.Extension)
#Write-Output ""
Move-Item -Path $_.FullName -Destination ($destDir + $_.BaseName + $_.Extension) -WhatIf
Write-Output ""
}
}
End {}
}
$inputPath = "D:\CRASH\ACCID - Lite Test zzz"
(Get-ChildItem -Path $inputPath -Recurse -Include *.dgn) | Remove-ExtraneousCADFiles
But I can't get the "IF" portion of my script to pass anything to the Remove-Item or Write-Output command. I've try other commands but I'm not having any luck, any help would be greatly appreciated.
These are an example of the files I'm trying to weed out to either delete or move:
Thanks, G
$_.Name -Like $char
-like
uses wildcard expressions, which must match the input as a whole.
Therefore, enclose your substring in *...*
:
$_.Name -like "*$char*"
Alternatively use -match
, which matches part of the input by default (substring matching):
$_.Name -match $char
However, note that -match
uses regular expressions (regexes), so if your - designed to be used verbatim - search string happens to contain regex metacharacters (e.g., .
, +
), you'll have to escape them (not necessary in your case):
$_.Name -match [regex]::Escape($char)
Note:
Direct use of .NET APIs also allows you to use the [string]
type's. .Contains()
method, which uses case-exact substring matching by default.
$_.Name.Contains($char)
does work for case-exact matching.However, this is at odds with PowerShell's fundamentally case-insensitive nature:
invariably so in Windows PowerShell: there is no overload with a case-insensitivity opt-in.
in PowerShell (Core) 7+ you can use a newly introduced overload of .Contains()
that permits case-insensitive matching on an opt-in basis, via an additional parameter, e.g.:
# PowerShell (Core) v7+ only
'foo'.Contains('OO', 'InvariantCultureIgnoreCase') # -> $true
While direct use of .NET APIs is a viable option - which is a testament to PowerShell's versatility - the flip side is that doing so is not PowerShell-idiomatic, for two reasons:
By default, .NET APIs are case-sensitive , whereas PowerShell is case-insensitive.
Calling .NET APIs:
requires method syntax (enclosure of arguments in (...)
, separating arguments with ,
- e.g, [double]::Parse('1.2', [cultureinfo]::InvariantCulture)
), which contrasts with PowerShell's shell-like argument-parsing mode (e.g., Get-Date -Year 1963
) as well as the use of PowerShell's operators in expression-parsing mode (e.g; 1.2 + 1
)
requires passing full file paths to .NET APIs, given that .NET's notion of the current directory usually differs from PowerShell's - see this answer.