1

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: enter image description here

Thanks, G


4
  • Wouldn't something like this do what you described in the your first paragraph? Get-ChildItem -LiteralPath 'D:\Temp' -Recurse -Filter '*.dgn' | ForEach-Object {if($_.Name -match $_.Name -match '^.*_ch_.*$') {<# Code to delete file $_ #>} else {<# Code to move file $_ #>}} Commented Sep 15, 2023 at 19:16
  • As an aside: You're declaring $paths (better :$Path (singular)) as the pipeline-binding parameter, so it's better to use it - not $input - in your process block. Commented Sep 15, 2023 at 19:31
  • @Darin, I will experiment with your suggestion of using a 'pipeline' format of my script. I'm not that familiar with its formatting. Commented Sep 20, 2023 at 13:02
  • 1
    @mklement0, Yes that of course makes sense thanks for the tip. Commented Sep 20, 2023 at 13:04

1 Answer 1

1

$_.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.

    • That is, $_.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.

Sign up to request clarification or add additional context in comments.

1 Comment

Thank You Very Much for your suggestions and detailed explanation of each. Very Helpful and illuminating, Peace.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.