What is the PowerShell equivalent to this Bash command? - powershell

I'm trying to create a CLI command to have TFS check out all files that have a particular string in them. I primarily use Cygwin, but the tf command has trouble resolving the path when run within the Cygwin environment.
I figure PowerShell should be able to do the same thing, but I'm not sure what the equivalent commands to grep and xargs are.
So, what would be the equivalent PowerShell version to the following Bash command?
grep -l -r 'SomeSearchString' . | xargs -L1 tf edit

Using some UNIX aliases in PowerShell (like ls):
ls -r | select-string 'SomeSearchString' | Foreach {tf edit $_.Path}
or in a more canonical Powershell form:
Get-ChildItem -Recurse | Select-String 'SomeSearchString' |
Foreach {tf edit $_.Path}
and using PowerShell aliases:
gci -r | sls 'SomeSearchString' | %{tf edit $_.Path}

I find it easier to grok using a variable, e.g.,
PS> $files = Get-ChildItem -Recurse |
Select-String 'SomeSearchString' |
%{$_.path} |
Select -Unique
PS> tf edit $files

Related

Seaching windows environment for a specific value

I want to search the windows environment variables for a specific string
Get-ChildItem -Path Env: | TEE-OBJECT -variable newvar1 | grep windir $newvar1
It works for first time
STDIN
windir C:\WINDOWS
and then fails the subsequent times
grep: Could not open 'System.Collections.DictionaryEntry'
How do i remove old variables from the dictionary (if that is the problem)?
Part 1 - Root Cause
Your core problem is grep windir $newvar1 - the command line parameters for grep are (from https://man7.org/linux/man-pages/man1/grep.1.html):
SYNOPSIS
grep [OPTION...] PATTERNS [FILE...]
DESCRIPTION
grep searches for PATTERNS in each FILE.
You're asking grep to search in a file ($newvar1), not the input stream. Each entry in $newvar1, gets serialised as the literal string System.Collections.DictionaryEntry so grep is basically looking for a file called System.Collections.DictionaryEntry, which doesn't exist.
Part 2 - Solution
The best bet is to go full idiomatic PowerShell and use #JPBlanc's answer, but if you're really wedded to grep just remove the trailing $newvar to use the input stream (stdin) instead of a file for input:
Get-ChildItem -Path Env: `
| TEE-OBJECT -variable newvar1 `
| grep windir
or, if you don't actually need the values stored in $newvar1 for downstream processing, just simply:
Get-ChildItem -Path Env: `
| grep windir
Part 3 - Why no error the first time?
Your original command works the first time because $newvar1 isn't defined yet, so it's equivalent to:
Get-ChildItem -Path Env: `
| TEE-OBJECT -variable newvar1 `
| grep windir $null
... so grep is defaulting to searching the input stream (stdin) rather than a file.
You can confirm this if you enable strict mode - you'll get this error from PowerShell instead:
Set-StrictMode -Version "Latest";
Get-ChildItem -Path Env: `
| TEE-OBJECT -variable newvar1 `
| grep windir $newvar1
# InvalidOperation:
# Line |
# 3 | | grep term $newvar1
# | ~~~~~~~~
# | The variable '$newvar1' cannot be retrieved because it has not been set.
The second time you run the commnad, $newvar1 is already initialised with the results from the first time, so it's equivalent to:
Get-ChildItem -Path Env: `
| TEE-OBJECT -variable newvar1 `
| grep windir "System.Collections.DictionaryEntry"
which, as we've seen, tells grep to look for a file called System.Collections.DictionaryEntry, and results in an error.
Part 4 - More details
Note that $newvar1 isn't defined in the first call to grep because Tee-Object only creates the variable in its End block once it's processed all of its pipeline input (see the source code for Tee-Object.cs on GitHub), which doesn't happen until the entire pipeline has been processed, including the downstream calls to grep.
Not that it's very useful, but you can force the first command to fail by doing this:
(Get-ChildItem -Path Env: | TEE-OBJECT -variable newvar1) `
| grep windir $newvar1
# /usr/bin/grep: System.Collections.DictionaryEntry: No such file or directory
Wrapping the first two expressions in a Grouping Operator forces the pipeline inside to be fully evaluated first, which means Tee-Object's End block creates the $newvar1 variable before grep is invoked, and we get the file-searching behaviour instead of the input stream behaviour.
You an try :
Get-ChildItem -Path Env: | Where-object {$_.value -like 'C:\Users*'}
Get-ChildItem returns a list of objects with properties Name and value. Then Where-object, allow you to filter on these properties, $_ representthe object, you can choose the operator (in this case -like) in the list of Powershell operators).

Wildcard certificate usage search with Powershell or Command prompt

I have a bash command
curl -v --silent https://abc.xyz/ 2>&1 | grep "CN=\*.xyz.com" -c
this works fine from a Ubuntu machine but I want to convert or use a similar command in Powershell or in CMD. I tried a bunch of variations like:
curl https://abc.xyz/ 2>&1 | Select-String -Pattern "CN=\*.xyz.com"
curl -E -Uri https://abc.xyz/ 2>&1 | Select-String -Pattern "CN=\*.xyz.com"
Invoke-WebRequest https://abc.xyz/ 2>&1 | Select-String -Pattern "CN=\*.xyz.com"
What I noticed in PS commands is, it's not outputting the common name to check the pattern with.
My actual need is to check if the wildcard cert used in https://abc.xyz/ or not.
What am I missing here?
My actual need is to check if the wildcard cert used in https://abc.xyz/ or not.
In this example, we'll check if a wildcard cert is used on msn.com:
$url = 'https://www.msn.com'
$req = [Net.HttpWebRequest]::Create($url)
$req.GetResponse() | Out-Null
$cerName = $req.ServicePoint.Certificate.GetName()
$cerName -match 'CN=\*\.msn\.com'
Output:
True

How to get the first word of output from a PowerShell command

I am trying to get first word from the output of this powershell command
Get-ChildItem -Path Cert:\Certificate::LocalMachine\My | findstr -i ecimas
Which is returning output like:
ffdrggjjhj ecims.example.com
How can I return the string "ffdrggjjhj" only?
You should just be able to split the output like so:
(Get-ChildItem -Path Cert:\Certificate::LocalMachine\My | findstr -i ecimas).split()[0]
Usually powershell looks more like this. Since there's objects, parsing isn't needed.
get-childitem Cert:\LocalMachine\TrustedPublisher | where subject -match wireless |
select -expand thumbprint
ABCDEFABCDEFABCDEFABCDEFABCDEFABCDEFABCD

gsutil - cp not processing each item in the pipeline

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.

equivalent of (dir/b > files.txt) in PowerShell

dir/b > files.txt
I guess it has to be done in PowerShell to preserve unicode signs.
Get-ChildItem | Select-Object -ExpandProperty Name > files.txt
or shorter:
ls | % Name > files.txt
However, you can easily do the same in cmd:
cmd /u /c "dir /b > files.txt"
The /u switch tells cmd to write things redirected into files as Unicode.
Get-ChildItem actually already has a flag for the equivalent of dir /b:
Get-ChildItem -name (or dir -name)
Simply put:
dir -Name > files.txt
In PSH dir (which aliases Get-ChildItem) gives you objects (as noted in another answer), so you need to select what properties you want. Either with Select-Object (alias select) to create custom objects with a subset of the original object's properties (or additional properties can be added).
However in this can doing it at the format stage is probably simplest
dir | ft Name -HideTableHeaders | Out-File files.txt
(ft is format-table.)
If you want a different character encoding in files.txt (out-file will use UTF-16 by default) use the -encoding flag, you can also append:
dir | ft Name -HideTableHeaders | Out-File -append -encoding UTF8 files.txt
Since powershell deals with objects, you need to specify how you want to process each object in the pipe.
This command will get print only the name of each object:
dir | ForEach-Object { $_.name }
Just found this great post, but needed it for sub directories as well:
DIR /B /S >somefile.txt
use:
Get-ChildItem -Recurse | Select-Object -ExpandProperty Fullname | Out-File Somefile.txt
or the short version:
ls | % fullname > somefile.txt
I am using:
(dir -r).FullName > somefile.txt
and with filter for *.log:
(dir -r *.log).FullName > somefile.txt
Note:
dir is equal to `gci` but fits the naming used in cmd
-r recursive (all subfolders too)
.FullName is the path only