Could someone please tell me how to avoid this error in the below circumstance?
$codegenDir = "Z:\Desktop\Song-Renamer"
$PowerShellRepresentation = dir -path $MyMusicFolder -recurse -include *.mp3,*.m4a,*.wma,*.flac,*.ape | select -ExpandProperty FullName | $codegenDir\codegen.exe -s 10 20 | Out-String | ConvertFrom-Json
What completely puzzles me is if simply omit $codegenDir (see below), the code operates correctly. I "think" I understand the concept of placing the expression first (ahead of other items in the pipeline. But I'm not sure how to rearrange/split this code so the expression in question the Codegen.exe external commandline is the first item in the pipeline (and still be able to pass data to it via pipeline).
$PowerShellRepresentation = dir -path $MyMusicFolder -recurse -include *.mp3,*.m4a,*.wma,*.flac,*.ape | select -ExpandProperty FullName | .\codegen.exe -s 10 20 | Out-String | ConvertFrom-Json
Ideally, it would be nice to do this using the least amount of code as possible.
Give the following a shot (only difference is the &):
$PowerShellRepresentation = dir -path $MyMusicFolder -recurse -include *.mp3,*.m4a,*.wma,*.flac,*.ape | select -ExpandProperty FullName | & $codegenDir\codegen.exe -s 10 20 | Out-String | ConvertFrom-Json
Here's a link to a technet article about executing commands in powershell in different ways.
Related
I am trying to create a small Powershell script which will copy a list of files matching a specific condition to a specified GCP Storage Bucket. I have gotten this far:
Get-ChildItem $Path | Where-Object { $_.psiscontainer -and $_.LastWriteTime -gt $Age } | Select-Object -ExpandProperty FullName | ft -hidetableheaders | gsutil -m cp -L log.log -r -n -I gs://bucket
But this only uploads the contents of the first folder in the list. I've tried using a foreach-object on the gsutil command, but I get an error due to not finding a URL to upload. When writing the output of the foreach to the console, the output appears to be completely empty.
I have confirmed that the entire line minus the gsutil command returns the correct folders from the path, so I know that the data is going into the pipeline. But I'm not sure why gsutil is only considering the first item in the pipeline.
Any assistance would be greatly appreciated, and thank you in advance!
My "c:\temp" folder has two child folders. When I run Get-ChildItem "c:\temp" | Where-Object {$_.psiscontainer} | Select-Object -ExpandProperty FullName | ft -hidetableheaders Powershell does output the names of the two child folders in c:\temp to the console:
C:\temp\child folder A
C:\temp\child folder B
However, if you capture the output of the command and examine the data type of each path output, you'll see that they are not strings, and I think gsutil requires a string as input when using -I (I think Ansgar Wiechers's comment is correct)
Run this:
$x = Get-ChildItem "c:\temp"| Where-Object {$_.psiscontainer} | Select-Object -ExpandProperty FullName | ft -hidetableheaders
write-host $x.Count
$x[0] | get-member
In my case, I see a count of 2 as expected (two child folders)
However, the datatype of the first item is not a string, it is a FormatEntryData:
$x[0] | get-member
shows the following on the console:
TypeName: Microsoft.PowerShell.Commands.Internal.Format.FormatEntryData
If you remove the | ft -hidetableheaders portion of your command, the data type of each item is a string
Run this:
$x = Get-ChildItem "c:\temp"| Where-Object {$_.psiscontainer} | Select-Object -ExpandProperty FullName
write-host $x.Count
$x[0] | get-member
You'll see a data type of TypeName: System.String for $x[0]
Does this work with gsutil?
As Ansgar Wiechers already said, do not use Format-* cmdlets unless you have a specific need to display formatted output to a user. If it still copies just the first directory the parameter -I may not work as it should. Try ... | ForEach-Object { gsutil -m cp -n -r $_ gs://... } instead.
I'm trying to generate a report for all WIM files in my MDT Deployment Share. Basically, I think need to do a ForEach loop on all the WIM files found. I have what I think should work but, obviously, it doesn't. How far off am I?
$WimPath = "G:\DeploymentShare\Operating Systems"
Get-ChildItem -Path $WimPath -Filter *.wim -Recurse -File | Select-Object -ExpandProperty VersionInfo | Select-Object FileName | ForEach-Object { Get-WindowsImage -ImagePath $_ }
The error I'm seeing is nagging about the Parameter being incorrect for the Get-WindowsImage command.
Get-WindowsImage : The parameter is incorrect.
At line:3 char:147
+ ... t-Object FileName | ForEach-Object { Get-WindowsImage -ImagePath $_ }
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
I'm thinking my Select-Object isn't working like I think it should or I'm not using the pipeline correctly in my Get-WindowsImage command.
I'm a PowerShell noob and don't fully understand this, but I think what is going on can be explained by first focusing on this part of the command:
Get-ChildItem -Path $WimPath -Filter *.wim -Recurse -File | Select-Object -ExpandProperty VersionInfo | Select-Object FileName
To get this far, we first get all the *.wim files in your path, we expand the VersionInfo property, and then select the FileName. In the console, that will show you results like this:
FileName
--------
[files here]
The trick is in understanding what PowerShell is telling you with this output. The fact you see a FileName header means the pipeline has a stream of Objects with one property named FileName. Then we send that stream of Objects to ForEach-Object and look at the $_ special variable.
Hopefully it is clearer now what is going on. Get-WindowsImage -ImagePath $_ wants to see a string value holding the path of a *.wim file. But we sent it an object with one property.
You can fix this a few ways... adding ExpandProperty to the second Select-Object would probably do it. But really there's no reason for two Select-Objects in there at all. I think you could just do this:
Get-ChildItem -Path $WimPath -Filter *.wim -Recurse -File | Select-Object -ExpandProperty FullName | ForEach-Object { Get-WindowsImage -ImagePath $_ }
And the trick here is the string representation you see in the shell from Get-ChildItem doesn't necessarily show every property in the object. There wouldn't be space. The FileName was always there, and you can see it by checking the Get-Member cmdlet, like so:
Get-ChildItem -Path $WimPath -Filter *.wim -Recurse -File | Get-Member
I would like to retrieve all (and only) second level directory names of my disk. For example, C:\folder1\folder2 and C:\folder1\folder3, I need to retrieve only folder2 and folder3.
I write this and the PS displays all the directory names:
Get-ChildItem -Recurse | ?{ $_.PSIsContainer} | Select-Object Name
I found this help, and I modify the previous command in this way:
Get-ChildItem -Recurse | `Where-Object {($_.directory -match '^*\\\S*$')} ` | ForEach-Object {?{ $_.PSIsContainer} | Select-Object Name }
but when I use it the PS doesn't display anything.
I can't understand why, someone can help me? Thank you!
Only files appear to have a .directory property, directories do not, so you will never get something which passes your (.directory matches a pattern) filter and also passes your (PSIsContainer) filter.
Except that your PSIsContainer filter doesn't work:
| ForEach-Object {?{ $_.PSIsContainer} | Select-Object Name }
this doesn't make sense; you can only filter the pipeline using ? with cmdlet | ? {}, you cannot filter at the start of a loop scriptblock with no input and get anything useful. This is running where-object {} over and over in a loop, - and that has no output.
Using -Recurse will be very slow, as you go into every single directory all the way to the end, and make [fileinfo] objects for all the files as well.
Apart from Matt's wildcard answer, assuming PS v3 or above, you could list all the directories in the root, and then all the directories inside those, and stop there:
Get-ChildItem c:\ -Directory | Get-ChildItem -Directory | Select -ExpandProperty Name
or
gci c:\ -Dir | ForEach { (gci $_ -Dir).Name }
You should just be able to use some fun wildcards to get what you want here.
Get-ChildItem \*\*\ | Where-Object{$_.PSIsContainer}
Or if you have at least PowerShell 3.0 this would be faster
Get-ChildItem \*\*\ -Directory
Then if you wanted just the names tack on | Select-Object -ExpandProperty Name
Here with full path, network compatible:
(Get-ChildItem "\\folder1\" -Dir).fullname | ForEach {(Get-ChildItem $_ -Dir).name}
Want it stored in an array?
$subfolders = (Get-ChildItem "\\folder1\" -Dir).fullname | ForEach {(Get-ChildItem $_ -Dir).name}
I have this folder in a directory. With different version on them.
CD1,CD2,CD3,CD4,CD5,CD6,CD7,CD8,CD9,CD11,CD12
I'm new to powershell, can anyone help me to get the latest version folder from the above folders? Here CD12 is the latest folder. I can't use last modified time because I copy them at the same time.
$FolderName=(Get-ChildItem C:\Current\CD |Where-Object {$_.name -like "*CD*"}| sort{$_.name.Substring(2,2)}|Select-Object Name -Last 1).Name)
Write-Host "$FolderName"
I tried the above script and it did not help. Can anyone help me?
The next new version is CD13, and the script should get that folder
You can try something like below
$max_version = Get-ChildItem "C:\Current\" | Where-Object {$_.PSIsContainer}
| Foreach-Object {$_.Name} | Foreach-object {$_ -replace "CD", ""}
| measure -maximum | Select-Object -expand Maximum
Write-host ("CD" + $max_version)
Which will result in CD12
You almost have it. When I tried to run your code, I ran into two errors. First, you have an extra ')' at the end of the line causing a syntax error. Second, your 'SubString()' call is failing because you're trying to get the 3rd and 4th characters of a string without a 4th character ("CD1"). You don't need the scriptblock to your Sort command, though. You can just sort on the Name field.
$FolderName = Get-ChildItem C:\7005\Hot-Fix\CD | where Name -like "CD*" | sort Name | Select-Object -Last 1 -ExpandProperty Name
As a side note, this uses the PowerShell 3 syntax for Where-Object and Sort-Object to omit the {}. And it uses the -ExpandProperty parameter to Select-Object, so you don't have to wrap the whole thing in parens to get the Name property.
You could try this:
#requires -v 3
$baseFolder='C:\7005\Hot-Fix\CD'
$folder=dir $baseFolder\CD* -Directory |
? basename -CMatch 'CD\d{1,}' |
sort #{e={'{0:0000}' -f [int]($_ -replace '\D')}} -Descending |
select -First 1
Notice, I'm considering case sensitive matching; also, $folder contains what you're looking for.
How can I delete all files in a directory that contain a string using powershell?
I've tried something like
$list = get-childitem *.milk | select-string -pattern "fRating=2" | Format-Table Path
$list | foreach { rm $_.Path }
And that worked for some files but did not remove everything. I've tried other various things but nothing is working.
I can easily get the list of file names and can create an array with the path's only using
$lista = #(); foreach ($f in $list) { $lista += $f.Path; }
but can't seem to get any command (del, rm, or Remove-Item) to do anything. Just returns immediately without deleting the files or giving errors.
Thanks
First we can simplify your code as:
Get-ChildItem "*.milk" | Select-String -Pattern "fRating=2" | Select-Object -ExcludeProperty path | Remove-Item -Force -Confirm
The lack of action and errors might be addressable by one of two things. The Force parameter which:
Allows the cmdlet to remove items that cannot otherwise be changed,
such as hidden or read-only files or read-only aliases or variables.
I would aslo suggest that you run this script as administrator. Depending where these files are located you might not have permissions. If this is not the case or does not work please include the error you are getting.
Im going to guess the error is:
remove-item : Cannot remove item C:\temp\somefile.txt: The process cannot access the file 'C:\temp\somefile.txt'
because it is being used by another process.
Update
In testing, I was also getting a similar error. Upon research it looks like the Select-String cmd-let was holding onto the file preventing its deletion. Assumption based on i have never seen Get-ChildItem do this before. The solution in that case would be encase the first part of this in parentheses as a sub expression so it would process all the files before going through the pipe.
(Get-ChildItem | Select-String -Pattern "tes" | Select-Object -ExpandProperty path) | Remove-Item -Force -Confirm
Remove -Confirm if deemed required. It exists as a precaution so that you don't open up a new powershell in c:\windows\system32 and copy paste a remove-item cmdlet in there.
Another Update
[ and ] are wildcard searches in powershell in order to escape those in some cmdlets you use -Literalpath. Also Select-String can return multiple hits in files so we should use -Unique
(Get-ChildItem *.milk | Select-String -Pattern "fRating=2" | Select-Object -ExpandProperty path -Unique) | ForEach-Object{Remove-Item -Force -LiteralPath $_}
Why do you use select-string -pattern "fRating=2"? You would like to select all files with this name?
I think the Format-Table Path don't work. The command Get-ChildItem don't have a property called "Path".
Work this snipped for you?
$list = get-childitem *.milk | Where-Object -FilterScript {$_.Name -match "fRating=2"}
$list | foreach { rm $_.FullName }
The following code gets all files of type *.milk and puts them in $listA, then uses that list to get all the files that contain the string fRating=[01] and stores them in $listB. The files in $listB are deleted and then the number of files deleted versus the number of files that contained the match is displayed(they should be equal).
sv -name listA -value (Get-ChildItem *.milk); sv -name listB -value ($listA | Select-String -Pattern "fRating=[01]"); (($listB | Select-Object -ExpandProperty path) | ForEach-Object {Remove-Item -Force -LiteralPath $_}); (sv -name FCount -value ((Get-ChildItem *.milk).Count)); Write-Host -NoNewline Files Deleted ($listA.Count - $FCount)/($listB.Count)`n;
No need to complicate things:
1. $sourcePath = "\\path\to\the\file\"
2. Remove-Item "$sourcePath*whatever*"
I tried the answer, unfortunately, errors seems to always come up, however, I managed to create a solution to get this done:
Without using Get-ChilItem; You can use select-string directly to search for files matching a certain string, yes, this will return the filename:count:content ... etc, but, internally these have names that you can chose or omit, the one you need is the "filename" to do this pipe this into "select-object" choosing the "FileName" from the output.
So, to select all *.MSG files that has the pattern of "Subject: Webservices restarted", you can do the following:
Select-String -Path .*.MSG -Pattern 'Subject: WebServices Restarted'
-List | select-object Filename
Also, to remove these files on the fly, you could pip into a ForEach statement with the RM command as follows:
Select-String -Path .*.MSG -Pattern 'Subject: WebServices Restarted'
-List | select-object Filename | foreach { rm $_.FileName }
I tried this myself, works 100%.
I hope this helps