ExecutionContext.InvokeCommand.ExpandString throws exception in PowerShell 4.0 - powershell

I have a script as below
[string]$newValue = Get-ConfigurationByType $setting.Value
After this line, the value of $newValue is
"http://ST-$($partner.Alias).vardiaforsakring.se/CardPaymentAgreementCallback.aspx"
In the loop, I call ExpandString
foreach ($partner in $partners)
{
$partnerSpecificValue =$ExecutionContext.InvokeCommand.ExpandString($newValue)
}
It throws exception
Exception calling "ExpandString" with "1" argument(s): "Object reference not set to an instance of an object."
At C:\Programs\Drops\Hydra_SE_v1.28\HydraDeploymentFunctions.ps1:342 char:5
+ $partnerSpecificValue = $ExecutionContext.InvokeCommand.ExpandString($newVal ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : NullReferenceException
But when I try to input hard-code string, it returns expected result without exception
$partnerSpecificValue =$ExecutionContext.InvokeCommand.ExpandString("http://ST-$($partner.Alias).vardiaforsakring.se/CardPaymentAgreementCallback.aspx")
The value of $partnerSpecificValue is
http://ST-secure.vardiaforsakring.se/CardPaymentAgreementCallback.aspx
Does anyone know a workaround to resolve this bug? Thank you very much. I am running PowerShell v4.0 on Windows Server 2012 R2.

ExpandString is problematic and doesn't work correctly in general case. I use this method instead:
function render() {
[CmdletBinding()]
param ( [parameter(ValueFromPipeline = $true)] [string] $str)
"#`"`n$str`n`"#" | iex
}
Example:
$x=#{test='test'}
'Hashtable x contains value $($x.test)' | render

I have a workaround for this bug.
https://social.technet.microsoft.com/Forums/en-US/5efc52d2-619c-4063-9a47-bc646c45e882/executioncontextinvokecommandexpandstring-throws-exception-in-powershell-40?forum=winserverpowershell

Related

Add elements to arry in powershell

I want to simply add some numbers to an array and then sort them via powershell, however, the following code seems to be wrong
$myArray = New-Object System.Collections.ArrayList
Foreach ($Name in $VMName) {
$Tokens = $Name.Split(".")
$myArray.Add($Tokens[$Tokens.Count-1])
}
Write-Host($myArray | Sort-Object)
The error is
+ $myArray.Add($Tokens[$Tokens.Count-1])
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : NotSupportedException
How can I fix that?
The variable $Name is something like 101.u18.uab.14 or 103.win10.template or 102.win7.pink.18 and so on. Each $Name has some . symbols and I want to tokenize them and get the last element for each of them. So, in this example, I want to see a sorted 14 18 template.
UPDATE:
The provided methods seems to be incorrect.
1- This method by Steven
$myArray = New-Object System.Collections.ArrayList
Foreach ($Name in $VMName) {
$Tokens = $Name.Split(".")
[Void]$myArray.Add($Tokens[-1])
}
shows this error
Exception calling "Add" with "1" argument(s): "Collection was of a fixed size."
At C:\Users\user\Desktop\get_ip_list.ps1:20 char:5
+ [Void]$myArray.Add($Tokens[-1])
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : NotSupportedException
2- This method by Santiago
$myArray = [Collections.Generic.List[string]]::new()
Foreach ($Name in $VMName) {
[Void]$myArray.Add($Name.Split(".")[-1])
}
Shows the following error
Exception calling "Add" with "1" argument(s): "Collection was of a fixed size."
At C:\Users\user\Desktop\get_ip_list.ps1:19 char:5
+ [Void]$myArray.Add($Name.Split(".")[-1])
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : NotSupportedException
If I have missed your point in the above codes, please let me know.
I think you are missing the first line from the error. However it looks like you are simply trying to add the last elements from the $Tokens array. In that case you don't need to reference the index like that, below should work:
$myArray = New-Object System.Collections.ArrayList
Foreach ($Name in $VMName) {
$Tokens = $Name.Split(".")
[Void]$myArray.Add($Tokens[-1])
}
Notice the addition of [Void] this will stop the .Add() method from returning the index number it just added to.
Also note you can create array list objects using casting like:
$myArray = [Collections.ArrayList]#()
Update to Address Continued Errors:
The only thing I can think of to cause the error "Collection was of a fixed size." is if you've previously type constrained the variable.
Example:
[String[]]$myArray = #()
# Posibly a whole bunch of other things happening maybe in the console or IDE.
$myArray = [Collections.ArrayList]#()
$myArray.Add('something')
Results:
Exception calling "Add" with "1" argument(s): "Collection was of a fixed size."
At line:1 char:1
+ $myArray.Add('something')...
In this case they type of the $myArray will not change to [Collections.ArrayList]. The problem will be transparent up until you try to use the .Add() method that won't work. This is because an array list is easily and therefore silently cast back to a [String[]] or [Object[]].
Note: If you were to run $myArray.IsFixedSize it would return "True".
My guess as to what's happening; at some point while developing your code or perhaps in the larger script, $myArray got type constrained, and stuck in the scope. This can definitely happen especially given the scope overlap in IDE's like PowerShell's ISE, and I think it happens in VSCode as well. If this is part of a larger script look for instances of $myArray to see if it's indeed type constrained and make corrections as needed. Otherwise a simply restarting your session might do the trick.
Honestly, not sure how could you be getting that error unless the array we're looping through is actually something different. Steven's answer should work fine, I'll put this code below just to show that the results we get are the ones you expect:
$col = [Collections.Generic.List[String]]::new()
$vmName = #(
'101.u18.uab.14'
'103.win10.template'
'102.win7.pink.18'
)
ForEach($name in $vmName)
{
$col.Add($name.Split('.')[-1])
}
if you want absolutly use array you can simply do it :
$Array=#()
$VMName | %{
$Value=($_.Split('.'))[-1]
$Array+= $Value
}
$Array| sort
Otherwise you can simply do it :
$VMName | %{($_.Split('.'))[-1]} | sort

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.

How to pass a custom enum to a function in powershell

When defining a function, how can you reference a custom enum?
Here's what I'm trying:
Add-Type -TypeDefinition #"
namespace JB
{
public enum InternetZones
{
Computer
,LocalIntranet
,TrustedSites
,Internet
,RestrictedSites
}
}
"# -Language CSharpVersion3
function Get-InternetZoneLogonMode
{
[CmdletBinding()]
param
(
[Parameter(Mandatory=$true)]
[JB.InterfaceZones]$zone
)
[string]$regpath = ("HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings\Zones\{0}" -f [int]$zone)
$regpath
#...
#Get-PropertyValue
}
Get-InternetZoneLogonMode -zone [JB.InternetZones]::TrustedSites
But this gives the error:
Get-ZoneLogonMode : Unable to find type [JB.InterfaceZones]. Make sure that the assembly that contains this type is loaded.
At line:29 char:1
+ Get-ZoneLogonMode -zone [JB.InternetZones]::TrustedSites
+ ~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (JB.InterfaceZones:TypeName) [], RuntimeException
+ FullyQualifiedErrorId : TypeNotFound
NB: I'm aware I could use ValidateSet for similar functionality; however that has the disadvantage of only having a name value; as opposed to allowing me to program using friendly names which are then mapped to ints in the background (I could write code for that; but enum seems more appropriate if possible).
I'm using Powershell v4, but ideally I'd like a PowerShell v2 compatible solution as most users are on that version by default.
Update
I've corrected the typo (thanks PetSerAl; well spotted).
[JB.InterfaceZones]$zone now changed to [JB.InternetZones]$zone.
Now I'm seeing error:
Get-InternetZoneLogonMode : Cannot process argument transformation on parameter 'zone'. Cannot convert value "[JB.InternetZones]::TrustedSites" to type
"JB.InternetZones". Error: "Unable to match the identifier name [JB.InternetZones]::TrustedSites to a valid enumerator name. Specify one of the following
enumerator names and try again: Computer, LocalIntranet, TrustedSites, Internet, RestrictedSites"
At line:80 char:33
+ Get-InternetZoneLogonMode -zone [JB.InternetZones]::TrustedSites
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidData: (:) [Get-InternetZoneLogonMode], ParameterBindingArgumentTransformationException
+ FullyQualifiedErrorId : ParameterArgumentTransformationError,Get-InternetZoneLogonMode
The ISE gave this one away to me but your attempted syntax was not completely incorrect. I was able to do this and get it to work.
Get-InternetZoneLogonMode -Zone ([JB.InternetZones]::TrustedSites)
Again, If you look at the highlighting you will see how I came to that conclusion.
Per comments by PetSerAl & CB:
Corrected typo in function definition
from [JB.InterfaceZones]$zone
to [JB.InternetZones]$zone
Changed function call
from Get-InternetZoneLogonMode -zone [JB.InternetZones]::TrustedSites
to Get-InternetZoneLogonMode -zone TrustedSites

Unable to Run [System.__ComObject].InvokeMember within PowerShell Function

I've been trying to write a program to access properties and methods of a 3rd party OLE DLL.
Below code runs fine.
[System.__ComObject].InvokeMember("AppName", [System.Reflection.BindingFlags]::GetProperty, $null, $appObj, $null)
As the invocation is going to be repetitive, I want to call a wrapper like below.
function Get-Property {
param(
$objOLE,
[String] $propertyName
)
[System.__ComObject].InvokeMember($propertyName,[System.Reflection.BindingFlags]::GetProperty,$null,$objOLE,$null)
}
When the script runs
Get-Property($appObj, "AppName")
I got this error:
Exception calling "InvokeMember" with "5" argument(s): "Method 'System.__ComObject.ToString' not found."
At F:\Scripts\test.ps1:21 char:36
+ [System.__ComObject].InvokeMember <<<< ($propertyName,[System.Reflection.BindingFlags]::GetProperty,$null,$objOLE,$null)
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException
This is confusing. Anybody has an insight? Thank you in advance.
Remember your function is a PowerShell function/command and not a .NET method i.e. don't use parens and don't comma separate args:
Get-Property $appObj AppName
The way you had it, your function gets one argument that is an array with two elements.

Psake Include method not working

I am writing a simple PS script with Psake and I have a problem when I try to include another ps1 file.
PS C:\CI> Include .\EnvSettings.ps1
I have this exception
Exception calling "Peek" with "0" argument(s): "Stack empty."
At C:\Users\Julien\Documents\WindowsPowerShell\Modules\psake\psake.psm1:227 char:2
+ $psake.context.Peek().includes.Enqueue(($pa));
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : InvalidOperationException
I had a look at psake.psm1 line 227 to see what's going on around
# .ExternalHelp psake.psm1-help.xml
function Include {
[CmdletBinding()]
param(
[Parameter(Position=0,Mandatory=1)][string]$fileNamePathToInclude
)
Assert (test-path $fileNamePathToInclude -pathType Leaf) ($msgs.error_invalid_include_path -f $fileNamePathToInclude)
$psake.context.Peek().includes.Enqueue((Resolve-Path $fileNamePathToInclude));
}
The code succesfully pass the Assert line.
The problem comes from the Resolve-Path $fileNamePathToInclude, it returns nothing...
If I try it from the command line it works fine.
Anyone experienced this problem before?
The way to include a file is not Include .\EnvSettings.ps1 , but just "dot source" the file :
. .\EnvSettings.ps1