when can I use methods and when command line options? - powershell

Why can I use split as a method and command line switch, but not join? How do I discover what flags (e.g. -join) an object supports?
> "a,b,c,d" -split ','
a
b
c
d
> "a,b,c,d".split(',')
a
b
c
d
> "a,b,c,d".split(',').join(';')
Method invocation failed because [System.String] does not contain a method named 'join'.
At line:1 char:1
+ "a,b,c,d".split(',').join(';')
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : MethodNotFound
> "a,b,c,d".split(',') -join ';'
a;b;c;d

Why can I use split as a method and command line switch, but not join?
Because String objects have a method Split(), but arrays don't have a method Join(), whereas -split and -join are operators provided by PowerShell.
The String class does have a (static) Join() method complementing Split(), though. You use it like this:
[String]::Join(',', ("a,b,c,d" -split ','))
Another thing you could do is set the output field separator ($OFS) to your delimiter character and embed your array in a string:
$OFS = ','
"$("a,b,c,d" -split ',')"
BTW, -split and Split() don't work the same way, so don't confuse them. The former uses a regular expression, the latter a character array.
PS C:\> 'a b' -split '\s+'
a
b
PS C:\> 'a b'.Split('\s+')
a b
PS C:\> 'a,b;c' -split (',', ';')
Cannot convert value ";" to type "System.Int32". Error: "Input string was not in
a correct format."
At line:1 char:9
+ 'a,b;c' -split (',', ';')
+ ~~~~~~
+ CategoryInfo : NotSpecified: (:) [], RuntimeException
+ FullyQualifiedErrorId : RuntimeException
PS C:\> 'a,b;c'.Split((',', ';'))
a
b
c
How do I discover what flags (e.g. -join) an object supports?
By reading the documentation. -join isn't a method, flag, or commandline switch. It's a PowerShell operator.

If you will do:
"String" | Get-Member
you will see that there is no Join Method available, only Split().
You can Use however the -Join Operator instead, which exist for -Split as well
In your Example:
"a,b,c,d".split(',') -join ";"
or Use the: [string]::Join() Class

Related

Check if powershell string contains an asterisk

I have a string : $row.TableName_Org[$i]
The value it contains is
This is a happy little asterisk: '*'
Now I want to do an IF based on the fact that the string contains an asterisk.
if($row.TableName_Org[$i] -Match "*") {
//Do Something
}
However gives me this error:
"*" - Kwantiteitsmeter {x,y} wordt door niets voorafgegaan. parseren
At C:\Users\hveijer\VS Code Repos\migratie-uitwissel\ReadData.ps1:33 char:4
+ $row.TableName_Org[$i] -match "*"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OperationStopped: (:) [], ArgumentException
+ FullyQualifiedErrorId : System.ArgumentException
As you've found out yourself, the escape character in PowerShells wildcard/glob mechanism is ` (backtick):
'string with * in it' -like '`*'
... but the backtick is also the escape character for expandable (double-quoted) strings, leading to situations with awkward double escaping, like:
$pattern = "${prefix}``*"
For this reason, I prefer to let PowerShell escape my search terms for me instead of doing it manually:
[wildcardpattern]::Escape("${prefix}*")
Turns out I had to escape the * using ` (slash backtick)

PowerShell split on "(" throws error: "Not enough )'s."

I've come across a weird "bug" or foible in PowerShell, trying to split a string on "(". Can anyone tell me what's going on, and if there is an easy work-around?
Here's the code:
$description = 'Get-ParsedData($Data)'
$description -split "("
Result:
parsing "(" - Not enough )'s.
At line:1 char:1
+ $description -split "("
+ ~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OperationStopped: (:) [], ArgumentException
+ FullyQualifiedErrorId : System.ArgumentException
I've tried using '(' as well as "(", and also
$description -split [char]0x0028
All result in the same error message: parsing "(" - Not enough )'s.
In the end I got around the problem with the following code, which works:
$description.SubString(0, $description.IndexOf('('))
However, I'm still curious as to why I was getting the original error and whether there is a simple work-around.
-split is a regular expression operator, and ( needs to be escaped (\():
$description -split "\("
The error message "Not enough )'s" might seem strange at first, but the reason ( needs to be escaped in regular expressions is that parentheses are used for grouping constructs:
PS C:\> 'abc' -split '(b)'
a
b
c
In the example above, we split on b, but "capture" it's value by enclosing it in ().
So when you pass the string "(" as a pattern, the regex engine sees it and goes "that ( is the start of a capture group", and since it can't find a corresponding ), it throws that error.
You can also use the [regex]::Escape() method to automatically escape any literal character in a regex pattern:
$splitPattern = [regex]::Escape("(")
$description -split $splitPattern
Alternatively, use the String.Split() method which only does simple substring replacement (and ( therefore doesn't need escaping):
$description.Split("(")

Cannot find an overload for "ToString" and the argument count: "1"

i'm not understanding what i'm doing wrong here since i seem to do the same thing but only one works.
i have a text file with a number list that i want to process (round the values):
39.145049
40.258140
41.400803
42.540093
43.664530
and here my script:
$a = get-content "input.txt"
$b = $a -join ','
$b | % {$_.ToString("#.###")}
this results in the following error:
Cannot find an overload for "ToString" and the argument count: "1".
At D:\script.ps1:9 char:9
+ $b | % {$_.ToString("#.###")}
+ ~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodException
+ FullyQualifiedErrorId : MethodCountCouldNotFindBest
however if i take the result after joining which is:
39.145049,40.258140,41.400803,42.540093,43.664530
and create the following script:
$b = 39.145049,40.258140,41.400803,42.540093,43.664530
$b | % {$_.ToString("#.###")}
it works just fine and outputs:
39.145
40.258
41.401
42.54
43.665
where am i going wrong on this one?
This happens as the inputs are not of the same type.
$b1 = $a -join ','
$b2 = 39.145049,40.258140,....
$b1.GetType().Name
String
$b2.GetType().Name
Object[]
As the input in the first case is a single string, foreach loop doesn't process it as a collection of decimal values but a single string. Thus,
$b | % {$_.ToString("#.###")}
Is going to do (as pseudocode):
'39.145049,40.258140,41.400803,42.540093,43.664530'.ToString("#.###")
Whilst the array version is doing
39.145049.ToString("#.###")
40.258140.ToString("#.###")
41.400803.ToString("#.###")
Powershell's able to figure out in the later case that the values are numbers. In the first case, it's just a string and thus the automatic conversion doesn't work.
What actually works in the first case is to cast the values as nubmers. Like so,
$a | % {$([double]$_).ToString("#.###")}
39,145
40,258
41,401
42,54
43,665

PowerShell - Add-Content- Unable to add multiple vars to a file

I'm trying to add an expression to a log file which contains Date,Time some data separated by ";". Unfortunately I get an error every time I change the position of the items in the -value brackets.
Whats seems to be wrong?
This is the code :
Add-Content -path C:\...\outlog.txt -Value($Date + ';' + $Time + ';Checked;' + $strFileName)
This is the error :
Cannot convert argument "1", with value: ";", for "op_Addition" to type "System.TimeSpan": "Cannot convert
value ";" to type "System.TimeSpan". Error: "String was not recognized as a valid TimeSpan.""
At C:\...\Untitled1.ps1:8 char:64
+ ... \outlog.txt -Value($($Date + ';' + $Time + ';'+ $str))
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodException
+ FullyQualifiedErrorId : MethodArgumentConversionInvalidCastArgument
Try this -
Add-Content -path C:\...\outlog.txt -Value("$Date; $Time; Checked; $strFileName")
If you look at get-help Add-Content -full, and look at the -value parameter, you will see -
-Value <Object[]>
Specifies the content to be added. Type a quoted string, such as "This data is for internal use only", or
specify an object that contains content, such as the DateTime object that Get-Date generates.
You cannot specify the contents of a file by typing its path, because the path is just a string, but you can
use a Get-Content command to get the content and pass it to the Value parameter.
Required? true
Position? 1
Default value None
Accept pipeline input? True (ByPropertyName, ByValue)
Accept wildcard characters? false
It says that it expects a quoted string or an object that contains content. It was missing in your case and hence the + operator was trying to add $date and time.

PowerShell 'Invoke-Expression' command with single quotation

I am trying to invoke the following the command which contains the single quotation, but I am not able to execute and returns as an error:
$expression = $snapshot.properties.activities[1].typeProperties.parameters.rawinputlocation = '$$Text.Format(`'wasb://document.blob.co
re.windows.net/{0:yyyy}/{0:MM}/{0:dd}/DocumentActivity/raw/{{*}}.csv'`, SliceEnd)'
Invoke-Expression $expression
Error:
Invoke-Expression $expression
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CategoryInfo : ParserError: (:) [Invoke-Expression], ParseException
FullyQualifiedErrorId : UnexpectedToken,Microsoft.PowerShell.Commands.InvokeExpressionCommand
This happens as the single quote, ', is escaped with a backtick, `.
The first one works, but the latter one is in the wrong order: the backtick is after the single quote. Consider the difference:
`'wasb://...csv'`
`'wasb://...csv`'