Home > Back-end >  Powershell Scan for missing files in multiple folders
Powershell Scan for missing files in multiple folders

Time:11-30

I'm checking for missing XYZ map tiles using Powershell, but coming unstuck in the nested loops. Essentially the map tiles exist from a "base" folder, within this base folder are multiple directories. Within each directory are the map tiles.

e.g.

C:\My Map\17\       # this is the Base folder, zoom level 17
C:\My Map\17\1234\  # this is a folder containing map tiles
C:\My Map\17\1234\30200.png  # this is a map tile
C:\My Map\17\1234\30201.png  # this is a map tile
C:\My Map\17\1234\30203.png  # this is a map tile, but we're missing 30202.png (have tiles either side)
C:\My Map\17\1234\30204.png  # this is a map tile
C:\My Map\17\1235\  # this is another folder containing map tiles [...]

So my idea is for each folder, scan for gaps where we have tiles each side and try to download them.

This is what I have so far:

$BasePath = "C:\_test\17\"

$ColumnDirectories = Get-ChildItem $BasePath -Directory

$ColumnDirectories | ForEach-Object {
    $ColumnDirectory = $ColumnDirectories.FullName 
    $MapTiles =  Get-ChildItem -Path $ColumnDirectory -Filter *.png -file
    $MapTiles | ForEach-Object {
        #Write-Host $MapTiles.FullName
        $TileName = $MapTiles.Name -replace '.png',''
        $TileNamePlus1 = [int]$TileName   1
        $TileNamePlus2 = [int]$TileName   2
        Write-Host $TileName
    }
}

But I'm getting Cannot convert the "System.Object[]" value of type "System.Object[]" to type "System.Int32".

Eventually I want to go Test-Path on each of $TileName, TileNamePlus1, $TileNamePlus2, and where the middle one doesn't exist to download it again.

e.g.

C:\My Map\17\1234\30201.png -- Exists
C:\My Map\17\1234\30202.png -- Not exists, download from https://somemapsrv.com/17/1234/30202.png
C:\My Map\17\1234\30203.png -- Exists

Any help appreciated! I'm fairly new to Powershell.

CodePudding user response:

The whole problem here is an understanding of how ForEach-Object loops work. Within the loop the automatic variable $_ represents the current iteration of the loop. So as suggested by the comments by dugas and Santiago Squarzon you need to change this line:

        $TileName = $MapTiles.Name -replace '.png',''

to this:

        $TileName = $_.Name -replace '\.png',''

Or more simply this (the BaseName property is the file name without the extension):

        $TileName = $_.BaseName

CodePudding user response:

Since all your png files have basenames as integer numbers, you could do something like this:

$BasePath = 'C:\_test\17'
$missing = Get-ChildItem -Path $BasePath -Directory | ForEach-Object {
    $ColumnDirectory = $_.FullName 
    # get an array of the files in the folder, take the BaseName only
    $MapTiles = (Get-ChildItem -Path $ColumnDirectory -Filter '*.png' -File).BaseName
    # create an array of integer numbers taken from the files BaseName
    $sequence = $MapTiles | ForEach-Object { [int]$_ } | Sort-Object

    $sequence[0]..$sequence[-1] | Where-Object { $MapTiles -notcontains $_ } | ForEach-Object {
        Join-Path -Path $ColumnDirectory -ChildPath ('{0}.png' -f $_)
    }
}

# missing in this example has only one file, but could also be an array of missing sequential numbered files

$missing  # --> C:\_test\17\1234\30202.png

If your file names have leading zero's, this won't work..

  • Related