Create new System.Collections.Generic.Dictionary object fails in PowerShell - powershell

PowerShell version: 5.x, 6
I'm trying to create a new object of System.Collections.Generic.Dictionary, but it fails.
I tried the following "versions":
> $dictionary = new-object System.Collections.Generic.Dictionary[[string],[int]]
New-Object : Cannot convert 'System.Object[]' to the type 'System.String' required by parameter 'ComObject'. Specified method is not supported.
At line:1 char:25
+ ... ry = new-object System.Collections.Generic.Dictionary[[string],[int]]
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [New-Object], ParameterBindingException
+ FullyQualifiedErrorId : CannotConvertArgument,Microsoft.PowerShell.Commands.NewObjectCommand
> $dictionary = new-object System.Collections.Generic.Dictionary[string,int]
New-Object : Cannot convert 'System.Object[]' to the type 'System.String' required by parameter 'ComObject'. Specified method is not supported.
At line:1 char:25
+ ... ionary = new-object System.Collections.Generic.Dictionary[string,int]
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [New-Object], ParameterBindingException
+ FullyQualifiedErrorId : CannotConvertArgument,Microsoft.PowerShell.Commands.NewObjectCommand
I know that I can use a hashtable under PowerShell, but I want to know how to create a dictionary via the above declaration.
What am I missing?
Thx

Used type name System.Collections.Generic.Dictionary[[string],[int]] contains a comma. By Creating and initializing an array:
To create and initialize an array, assign multiple values to a
variable. The values stored in the array are delimited with a
comma…
Hence, you need to escape the comma (read the about_Escape_Characters and about_Quoting_Rules help topics). There are more options:
In Windows PowerShell, the escape character is the backtick (`),
also called the grave accent (ASCII 96).
$dictionary = new-object System.Collections.Generic.Dictionary[[string]`,[int]]
Quotation marks are used to specify a literal string. You can enclose
a string in single quotation marks (') or double quotation marks
(").
$dictionary = new-object "System.Collections.Generic.Dictionary[[string],[int]]"
or
$dictionary = new-object 'System.Collections.Generic.Dictionary[[string],[int]]'

The problem is how powershell is interpreting your argument.
When you include a comma in your string, it's now trying to bind
'System.Collections.Generic.Dictionary[[string]', '[int]]'
to the -TypeName parameter which is of type <string[]> or in the error message, <System.Object[]>. This can be solved by properly quoting your argument so it matches the expected parameter binding of <string>:
New-Object -TypeName 'System.Collections.Generic.Dictionary[[string], [int]]'

As well as the accepted answer, a dictionary can also be initialised using the syntax in the code block below, which:
removes the need to escape any characters
is much cleaner (in my opinion)
gives you intellisense (tested in PowerShell & PowerShell ISE)
$dictionary = [System.Collections.Generic.Dictionary[string,int]]::new()
... where string and int are .NET types.

Related

Powershell Registry String to Workable Date

Cannot convert string format to date using parse exact.
Registry contains the following string value:
2022-10-18T12:40:25
I need to convert this string to a date field in order to count number of days since (compared to today).
$startdate =
Get-ItemProperty -Path 'HKLM:SOFTWARE\Adobe\Acrobat Distiller\DC\Installer\' |
select-object 'Dummy'
[datetime]::parseexact($startdate,'dd/MM/yyyy HH:mm',$null)
$today = (([datetime]::Now))
$x = New-TimeSpan -Start $startdate -End $today
"$($x.days) $("days have passed since") $($startdate)"
Cannot find an overload for "parseexact" and the argument count: "3".
At line:2 char:1
+ [datetime]::parseexact($startdate,'dd/MM/yyyy HH:mm',$null)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodException
+ FullyQualifiedErrorId : MethodCountCouldNotFindBest
New-TimeSpan : Cannot bind parameter 'Start'. Cannot convert value "#{dummy=2022-10-18T12:40:25}" to type "System.DateTime". Error: "Cannot convert the "#{dummy=2022-10-18T12:40:25}" value of type
"Selected.System.Management.Automation.PSCustomObject" to type "System.DateTime"."
At line:5 char:26
+ $x = New-TimeSpan -Start $startdate -End $today
+ ~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [New-TimeSpan], ParameterBindingException
+ FullyQualifiedErrorId : CannotConvertArgumentNoMessage,Microsoft.PowerShell.Commands.NewTimeSpanCommand
days have passed since #{dummy=2022-10-18T12:40:25}
Your primary problem is that you need to use -ExpandProperty, if you use Select-Object, or you can use simple property access:
Select-Object (select) by default returns a [pscustomobject] instance that has the requested properties - even when you're only asking for a single property. To get only that property's value, use the -ExpandProperty parameter instead of the (possibly positionally implied) -Property parameter - see this answer for details and alternatives, notably the ability to simply use (...).SomeProperty
Therefore, the simplest solution is:
$startdate = (
Get-ItemProperty 'HKLM:SOFTWARE\Adobe\Acrobat Distiller\DC\Installer'
).Dummy
Or, in PSv5+, using Get-ItemPropertyValue:
$startdate =
Get-ItemPropertyValue 'HKLM:SOFTWARE\Adobe\Acrobat Distiller\DC\Installer' Dummy
As for then parsing the resulting string into a [datetime] instance:
The format string you're passing to ::ParseExact(), doesn't match your input string, and TheMadTechnician's answer shows how to fix that (see this answer's bottom section for further considerations).
However, you can more simply use a [datetime] cast, which recognizes your string format as-is, irrespective of what culture is currently in effect:
[datetime] '2022-10-18T12:40:25'
In essence, PowerShell translates the above into the following ::Parse() call:
[datetime]::Parse('2022-10-18T12:40:25', [cultureinfo]::InvariantCulture)
In general, for full robustness when using format strings, it is best to escape :, /, and . (if present) with \, so as if they are to be interpreted literally, i.e by only matching literally during parsing and being included literally when formatting output (by default, they're considered placeholders for the target culture's separators):
[datetime]::ParseExact(
'2022-10-18T12:40:25',
'yyyy-MM-ddTHH\:mm\:ss', # \-escaping ensures literal matching
[cultureinfo]::InvariantCulture
)
Note: In this particular case, [cultureinfo]::InvariantCulture alone would be sufficient for robustness, given that this culture uses : as the time separator.
You get an error because your second argument doesn't match the format of the datetime.
[datetime]::parseexact($startdate,'yyyy-MM-ddTHH:mm:ss',$null)

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 error 'can't call null-value expresssion' [duplicate]

I am simply trying to create a powershell script which calculates the md5 sum of an executable (a file).
My .ps1 script:
$answer = Read-Host "File name and extension (ie; file.exe)"
$someFilePath = "C:\Users\xxx\Downloads\$answer"
If (Test-Path $someFilePath){
$stream = [System.IO.File]::Open("$someFilePath",[System.IO.Filemode]::Open, [System.IO.FileAccess]::Read)
$hash = [System.BitConverter]::ToString($md5.ComputeHash($stream))
$hash
$stream.Close()
}
Else{
Write-Host "Sorry, file $answer doesn't seem to exist."
}
Upon running my script I receive the following error:
You cannot call a method on a null-valued expression.
At C:\Users\xxx\Downloads\md5sum.ps1:6 char:29
+ $hash = [System.BitConverter]::ToString($md5.Compute ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
To my understanding, this error means the script is attempting to do something, but another part of the script does not have any information to permit the first part of the script to work properly. In this case, $hash.
Get-ExecutionPolicy outputs Unrestricted.
What is causing this error?
What exactly is my null valued expression?
Any help is appreciated. I apologize if this is trivial and will continue my research.
References:
http://blogs.technet.com/b/heyscriptingguy/archive/2013/03/27/troubleshoot-the-invokemethodonnull-error-with-powershell.aspx
How to get an MD5 checksum in PowerShell
The simple answer for this one is that you have an undeclared (null) variable. In this case it is $md5. From the comment you put this needed to be declared elsewhere in your code
$md5 = new-object -TypeName System.Security.Cryptography.MD5CryptoServiceProvider
The error was because you are trying to execute a method that does not exist.
PS C:\Users\Matt> $md5 | gm
TypeName: System.Security.Cryptography.MD5CryptoServiceProvider
Name MemberType Definition
---- ---------- ----------
Clear Method void Clear()
ComputeHash Method byte[] ComputeHash(System.IO.Stream inputStream), byte[] ComputeHash(byte[] buffer), byte[] ComputeHash(byte[] buffer, int offset, ...
The .ComputeHash() of $md5.ComputeHash() was the null valued expression. Typing in gibberish would create the same effect.
PS C:\Users\Matt> $bagel.MakeMeABagel()
You cannot call a method on a null-valued expression.
At line:1 char:1
+ $bagel.MakeMeABagel()
+ ~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
PowerShell by default allows this to happen as defined its StrictMode
When Set-StrictMode is off, uninitialized variables (Version 1) are assumed to have a value of 0 (zero) or $Null, depending on type. References to non-existent properties return $Null, and the results of function syntax that is not valid vary with the error. Unnamed variables are not permitted.

PowerShell ValidateLength with Read-Host

I am trying to use ValidateLength declaration with Read-Host, however I cannot get it to work. If I use it without Read-Host it works flawless. Here are some basic examples:
[ValidateLength(1,3)]$test = '123'
[ValidateLength(1,3)]$test1 = Read-Host
123
Attribute cannot be added because it would cause the variable test1 with value
123 to become invalid.
At line:1 char:1
+ [ValidateLength(1,3)]$test1 = Read-Host
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : MetadataError: (:) [], ValidationMetadataExcepti
on
+ FullyQualifiedErrorId : ValidateSetFailure
Is it possible to use ValidateLength declaration with Read-Host?
Declare your Read-Host as a string (since ValidateLength can not accept anything except a string) and the problem is solved.
[ValidateLength(1,3)]$test1 = [String](Read-Host "Input")
I am not sure why you have to cast a type on it, but it solves the problem.

powershell function parameter types

have the following function:
function appendToSB([System.Text.StringBuilder]$sb,
[string]$value){
[void]$sb.append($value)
$sb
}
$sb = new-object -typename system.text.stringbuilder
$sb = appendToSb($sb, "1,")
$sb.tostring() | out-host
i want to build string using StringBuilder using my function for that, but i receive the following error:
appendToSB : Cannot process argument transformation on parameter 'sb'.
Cannot convert the "System.Object[]" value of ty pe "System.Object[]"
to type "System.Text.StringBuilder". At E:\powershell\test.ps1:8
char:11
+ appendToSb([system.text.stringbuilder]$sb, "1,")
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidData: (:) [appendToSB], ParameterBindingArgumentTransformationException
+ FullyQualifiedErrorId : ParameterArgumentTransformationError,appendToSB
does anybody can explain how function/function parameter/return values works in powershell?
Classic PowerShell issue. You don't use parens or comma separated args when calling commands or functions e.g.:
appendToSb $sb "1,"
You only use that syntax when calling .NET methods. If you use Set-StrictMode -Version 2 it will catch this sort of issue. What you passed ($sb, "1,") is how you would pass an array to a single parameter. Technically the parens aren't needed but don't change the value i.e. you could pass an array like this as well $sb, ",".