I have lots of text output from a tool that I want to parse in Powershell 2.0. The output is nicely formatted so I can construct a regex to pull out the data I want using select-string. However getting the subsequent matches out of select-string seems long-winded. There has to be a shorter way?
This works:
p4 users | select-string "^\w+(.\w+)?" |
select -Expand Matches | %{p4 changes -u $_.Value}
But All those Matches and Values are verbose. There's nothing obvious in the select-string help file, but is there a way to make it pump out just the regex matches as strings? A bit like:
p4 users | select-string "^\w(.\w+)?" -ImaginaryMagicOption | %{p4 changes -u $_}
In this case, it may be a bit easier to use -match e.g.:
p4 users | Foreach {if ($_ -match '^\w+(.\w+)?') { p4 changes -u $matches[0] }}
This is only because the output of Select-String is MatchInfo object that buries the Matches info one level down. OTOH it can be made to work:
p4 users | Select-String "^\w+(.\w+)?" |
Foreach {p4 changes -u $_.Matches[0].Value}
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 am listing files in a directory along with their epoch time (being used on a Linux box, for centralized file management).
I'm having issues getting it to join 2 fields with a comma in between.
folder structure is
c:\temp\test
test1.txt
test2.txt
Expected output:
File: test1.txt,1518167449
File: test2.txt,1518167449
i have all the information in:
(Get-ChildItem C:\temp\test | select name, #{name='lastwritetime';Expression={[int][double]::Parse((Get-Date $_.LastWriteTime -UFormat %s))}})
gives the output
Name lastwritetime
test1.txt 1518167449
test2.txt 1518167455
but i'm not able to join them so they look in the correct format (with the comma join).
You could do something like this:
$Files = (Get-ChildItem C:\temp\test | select name, #{name='lastwritetime';Expression={[int][double]::Parse((Get-Date $_.LastWriteTime -UFormat %s))}})
$Files | ForEach-Object {
"$($_.Name),$($_.LastWriteTime)"
}
This uses a ForEach-Object loop that iterates through each file and outputs a string. The string uses subexpressions $( ) to allow us to access the two properties we want and interpolate them in the string with a comma between them.
Note that you don't have to use a $Files variable, you could instead chain the ForEach-Object command on the end of your Select, but because that command is already quite long this makes the code a bit cleaner.
Another option is this:
$Files | ForEach-Object {
"{0},{1}" -f $_.Name,$_.LastWriteTime
}
Its up to you as to which you feel is more readable.
You could also consider using the ConvertTo-CSV cmdlet, although that will also add quote marks around each value. If your ultimate destination is CSV though using that or Export-CSV is cleaner/simpler.
I have been trying to write a powershell script (my first) to
parse out only the folders within a directory
select only those folders matching a specific naming convention ('SEASON YEAR')
switch the order of the elements of the name ('YEAR SEASON')
I eventually used the program BulkRenameUtility to do this using the regexp ^(\w+) (\d+) and switching the token order to $2 $1 -- however, I still am learning Powershell and would like to be able to do this without using an external program.
So, to re-iterate, at C:\Users\Test
there are folders and files.. some of the folders are named Spring 2015, Fall 2014, for example. However, other folders have names such as geogex. Files have names such as ENG1A SPRING 2015.odtand untitled_0.odt.
How do I only change the names of the folders named like "Spring 2015" to read "2015 Spring", "2014 Fall" etc. ?
I was able to use
gci | ? {$_.PSIsContainer} | select-string -pattern '\d+'
to accomplish 1 and 2 but am stuck on using this to do part 3: actually rename by reversing the elements of the name. I tried putting the above within a variable and like so:
gci | ? {$_.PSIsContainer} | select-string -pattern '\d+' | %{$data = $_.line; Write-Output "$data"};
however, while the above outputs exactly the folders I want the array $data seems to only hold the last line of output. Such that:
gci | ? {$_.PSIsContainer} | select-string -pattern '\d+' | %{$data = $_.line; Write-Output "$data"};
$data
will output:
test 123
test 321
test 321
I am unsure if this is even the a valid direction to begin with.
Any help would be greatly appreciated.
This should get the job done.
$Path = "C:\Users\Test"
$regex = "^(Spring|Summer|Fall|Winter)\s+\d{4}$"
Get-ChildItem $Path |
Where-Object {$_.PSIsContainer -and $_.Name -match $regex} |
Rename-Item -NewName {$split = $_.Name -split "\s+"; "{0} {1}" -f $split[1],$split[0]}
We use that regex to filter out the folder that fit your convention. Should be a little more targeted using specific season names. The year is a little more lacked by just looking for 4 numbers.
Other ways to do it but for the rename I just split the name on the space and reversed the output using the -f format operator.
I am newbie on powershell. Today I tried something very simple
Alias | sls -Pattern 'echo'
which produced echo, but what I want is Alias echo -> Write-Out.
In bash, you can just do
alias | grep 'echo'
My question is why sls does not work. BTW, if I replace sls with findstr, it worked.
If you want to get an alias with a particular name you can do:
alias -name echo
The echo -> Write-Out is the DisplayName:
(alias -name echo).DisplayName
The Get-Alias command returns a sequence of objects, each of which represents a single command alias. When displayed in powershell, these objects are formatted as a table containing the CommandType, Name and ModuleName properties.
When you pipe into findstr, it is the string representations of these columns which are being filtered, so any match displays the whole table row:
Alias echo -> Write-Output
When you pipe into Select-String each object is being bound to the -InputObject parameter of the Select-String cmdlet. Since Select-String operates on text, it just calls ToString on the received object to get its string representation.
ToString only returns the Name property. You can see this by executing the following:
alias | %{$_.tostring()}
Therefore any matches from Select-String only match on the alias name.
select-string only behaves like grep when used with a text file. With a powershell object, the behavior changes (as Lee explained in his answer).
This can be demonstrated with:
alias > out.txt; cat out.txt | sls -pattern 'echo'
Which returns Alias echo -> Write-Output because now slsis operating on a text file.
The other solutions to do what you want are:
alias | where DisplayName -like '*echo*'
alias | out-string -stream | sls -pattern 'echo'
This converts the powershell object to a string so that sls works like grep.
I have a json-formatted file that contains a number of lines starting with "url": "someValue", with spacing before, like this:
"url": "http://www.mydomain.som/assets/js/lib/less-1.2.1.min.js",
Could someone answer how I could extract all those lines and copy the to another file and sort that list alphabetically with a Powershell command? I have just started using Powershell and have no clue how to do this and would be very grateful if someone could answer this.
/Christian
Get-Content .\json.txt |
Where-Object {$_ -match '"url": "http://www.mydomain.som/.+",'} |
Set-Content .\URLs.txt
Not Powershell but following command could be all it takes.
type YourFile | find "url" | sort > YourNewfile
(Get-Content "c:\MyFilePath.txt") |
foreach { $_ -match '"url":/s*"http:(.*?)"," } |
Set-Content "c:\MyFilteredList.txt"
You might have to tweak the regular expression (not tested).