I work with Perforce and often have many local changes after unshelving that I want to remove. Using PowerShell I can print out the files I want removed but the output string still contains substrings I would like to see removed.
Get-ChildItem -Recurse -Include ("*.uasset", "*.umap") -Attributes !ReadOnly "C:\Unreal\Project\Content" | ForEach-Object {p4 have $_.FullName}
This will output files I only have locally as "C:\Unreal\Project\File.uasset - file(s) not on client." and others as "//Project/Content/File.uasset#12 - C:\Unreal\Project\File.uasset"
The files I don't have on client I want to Remove-Items on, and the other run p4 sync
but am currently stuck even getting Write-Host to output either with only the local path.
I've tried filtering the outputs using Select-String, to then attempt and only output the paths like
Get-ChildItem -Recurse -Include ("*.uasset", "*.umap") -Attributes !ReadOnly "C:\Unreal\Project\Content" | ForEach-Object {p4 have $_.FullName} | Select-String " not on client." | Write-Host ($_ -split ' - file(s)')[0]
The full string "C:\Unreal\Project\File.uasset - file(s) not on client." still gets printed
Also attemped filtering inside the loop like this
Get-ChildItem -Recurse -Include ("*.uasset", "*.umap") -Attributes !ReadOnly "C:\Unreal\Project\Content" | ForEach-Object { if ((p4 have $_.FullName) -like "*not on client." { Write-Host ($_ -split ' - file(s)')[0] } }
Again, full string is printed to terminal.
I have tried variation of split like $_.Split(' - file(s)', 2)[0]
but still full string gets printed. And just to make sure, I tried different indices if it was the case that split would have full string as first index then have results of split.
Example of unfiltered output
> Get-ChildItem -Recurse -Include ("*.uasset", "*.umap") -Attributes !ReadOnly "C:\Unreal\Project\Content" | ForEach-Object {p4 have $_.FullName}
C:\Unreal\Project\Content\Example_01.uasset - file(s) not on client.
C:\Unreal\Project\Content\Example_02.uasset - file(s) not on client.
C:\Unreal\Project\Content\Example_03.uasset - file(s) not on client.
//Project/Content/Example_04.uasset#11 - C:\Unreal\Project\Content\Example_04.uasset
//Project/Content/Example_05.uasset#6 - C:\Unreal\Project\Content\Example_05.uasset
//Project/Content/Example_06.uasset#1 - C:\Unreal\Project\Content\Example_06.uasset
//Project/Content/Example_07.umap#7 - C:\Unreal\Project\Content\Example_07.umap
//Project/Content/Example_08.umap#73 - C:\Unreal\Project\Content\Example_08.umap
C:\Unreal\Project\Content\Example_09.uasset - file(s) not on client.
C:\Unreal\Project\Content\Example_10.uasset - file(s) not on client.
C:\Unreal\Project\Content\Example_11.uasset - file(s) not on client.
C:\Unreal\Project\Content\Example_12.uasset - file(s) not on client.
C:\Unreal\Project\Content\Example_13.uasset - file(s) not on client.
Guess one could note also, that the p4 command have will print the "file(s) not on client" to stderr as this is an error/warning - found after I gave up on powershell and just did it in python.
Putting together everbody's efforts:
# Get the files
Get-ChildItem -Recurse -Include ('*.uasset', '*.umap') -Attributes !ReadOnly 'C:\Unreal\Project\Content' |
# run "p4 have" on every file
# we are only interested in the results sent to stdErr\Error Stream, so redirect it to stdOut\Success Stream
ForEach-Object { p4 have $_.FullName 2>&1 } |
# Filter keeping only the ones we need
Where-Object { $_ -like '*not on client.' } |
# for each string, remove the undesidered parts(everything after the filename)
ForEach-Object { $_.Substring($_.IndexOf(' - file(s)')) }
It returns a string array of filenames with full path