"Set-PSDebug -Trace 2" causes a variable assignment to fail - powershell

This two-line PS script fails if debug tracing is set to level 2:
Set-PSDebug -Trace 2
$Process = Start-Process -FilePath ping -ArgumentList localhost -NoNewWindow -PassThru -Wait
It fails with this error:
Cannot convert value to type System.String.
At line:1 char:1
+ $Process = Start-Process -FilePath ping -ArgumentList localhost -NoNe ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvalidCastFromAnyTypeToString
If I set -Trace 1 or no tracing, it works. If I don't try to assign $Process in -Trace 2, it works.
I wouldn't expect Set-PSDebug to modify the execution environment, but that seems to be the case here. Is this expected behavior? Or perhaps a bug in PowerShell?
Version information:
PS C:\Users\Eric> $PSVersionTable
Name Value
---- -----
PSVersion 5.1.19041.2364
PSEdition Desktop
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...}
BuildVersion 10.0.19041.2364
CLRVersion 4.0.30319.42000
WSManStackVersion 3.0
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1

Related

Function pipeline support, can't bind argument to parameter

I created following simple funcion, where the parameter supports input from pipeline:
function Write-Log {
[CmdletBinding()]
param (
# Lines to log
[Parameter(Mandatory , ValueFromPipeline )]
[string[]]
$PipeLineLoglines
)
process {
Write-Host $_
}
}
If I call the function via e.g. :
"test1", "test2" | Write-Log
It works as expected, but if I'm forwarding an empty string down the pipeline I get the folowing error:
C:\> "test1", "", "test2" | Write-Log
test1
Write-Log : Cannot bind argument to parameter 'PipeLineLoglines' because it is an empty string.
At line:1 char:24
+ "test1", "", "test2" | Write-Log
+ ~~~~~~~~~
+ CategoryInfo : InvalidData: (:String) [Write-Log], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorEmptyStringNotAllowed,Write-Log
test2
I'm using PowerShell.Core:
C:\> $PSVersionTable
Name Value
---- -----
PSVersion 6.2.0
PSEdition Core
GitCommitId 6.2.0
OS Microsoft Windows 10.0.17763
Platform Win32NT
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
WSManStackVersion 3.0
Can someone explain why an empty string causes this error?
Thx
It's because the parameter is Mandatory, and it's considered that an empty string did not satisfy that condition. Given that there are specific validation attributes to test for that, I don't like this behavior, but that's the way it is.
There is an attribute that can help you though, [AllowEmptyString()]:
function Write-Log {
[CmdletBinding()]
param (
# Lines to log
[Parameter(Mandatory , ValueFromPipeline )]
[AllowEmptyString()]
[string[]]
$PipeLineLoglines
)
process {
Write-Host $_
}
}

PowerShell cmdlet Test-NetConnection not available

I noticed that the cmdlet Test-NetConnection was not installed on Server 2012. Since Server 2012 comes with PowerShell version 3 so I thought it might help to update to the latest version 5.1.
I did the update but the cmdlet Test-NetConnection is still not available.
Only Test-Connection is present, but I need Test-NetConnection to test ports.
How can I get Test-NetConnection now?
PS C:\Windows\system32> $PSVersionTable
Name Value
---- -----
PSVersion 5.1.14409.1005
PSEdition Desktop
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...}
BuildVersion 10.0.14409.1005
CLRVersion 4.0.30319.34209
WSManStackVersion 3.0
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
PS C:\Windows\system32> Get-Command Test-NetConnection
Get-Command : The term 'Test-NetConnection' is not recognized as the name of a cmdlet,
function, script file, or operable program. Check the spelling of the name, or if a path
was included, verify that the path is correct and try again.
At line:1 char:1
+ Get-Command Test-NetConnection
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (Test-NetConnection:String) [Get-Command], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException,Microsoft.PowerShell.Commands.GetCommandCommand
The availability of many cmdlets is tied to the Windows version, not the PowerShell version. If you can't upgrade your Windows version you can't have Test-NetConnection.
You could use a commandline port scanner like nmap or scanline for port tests, or you could connect to the port(s) yourself:
function Test-Port($server, $port) {
$client = New-Object Net.Sockets.TcpClient
try {
$client.Connect($server, $port)
$true
} catch {
$false
} finally {
$client.Dispose()
}
}
$ipaddress = "serverName"
$port = "portNum"
$connection = New-Object System.Net.Sockets.TcpClient($ipaddress, $port)
if ($connection.Connected) {
Write-Host "Success"
} else {
Write-Host "Failed"
}

Why are LCM members missing from Get-DscLocalConfigurationManager result?

I have two different Windows Server 2012 R2 machines (built at different times) and I want to check the LCM state in my PS script.
One server returns the LCMState from Get-DscLocalConfigurationManager, the other doesn't return the LCMState or any other LCM members.
Is this due to an older version of the WMF?
I had a look at https://serverfault.com/questions/627386/what-version-of-windows-management-framework-is-installed but both servers report the same PSVersion.
On the new working server:
PS C:\> Get-DscLocalConfigurationManager
ActionAfterReboot : ContinueConfiguration
AllowModuleOverwrite : False
CertificateID :
ConfigurationID :
ConfigurationMode : ApplyAndMonitor
ConfigurationModeFrequencyMins : 15
Credential :
DebugMode : {NONE}
DownloadManagerCustomData :
DownloadManagerName :
LCMCompatibleVersions : {1.0}
LCMState : Idle
LCMVersion : 1.0
RebootNodeIfNeeded : False
RefreshFrequencyMins : 30
RefreshMode : PUSH
PSComputerName :
PS C:\> (get-module PSDesiredStateConfiguration).Version
Major Minor Build Revision
----- ----- ----- --------
1 0 -1 -1
PS C:\> $PSVersionTable
Name Value
---- -----
PSVersion 4.0
WSManStackVersion 3.0
SerializationVersion 1.1.0.1
CLRVersion 4.0.30319.42000
BuildVersion 6.3.9600.18728
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0}
PSRemotingProtocolVersion 2.2
On the older server the LCM members are not present:
PS C:\> Get-DscLocalConfigurationManager
AllowModuleOverwrite : False
CertificateID :
ConfigurationID :
ConfigurationMode : ApplyAndMonitor
ConfigurationModeFrequencyMins : 30
Credential :
DownloadManagerCustomData :
DownloadManagerName :
RebootNodeIfNeeded : False
RefreshFrequencyMins : 15
RefreshMode : PUSH
PSComputerName :
PS C:\> (Get-Module PSDesiredStateConfiguration).Version
Major Minor Build Revision
----- ----- ----- --------
1 0 -1 -1
PS C:\> $PSVersionTable
Name Value
---- -----
PSVersion 4.0
WSManStackVersion 3.0
SerializationVersion 1.1.0.1
CLRVersion 4.0.30319.34003
BuildVersion 6.3.9600.16394
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0}
PSRemotingProtocolVersion 2.2
How do I obtain the LCM state on the older server?
You have a different build on the first system (6.3.9600.18728). WMF 4.0 had a November 2014 update where some of these were introduced. So, the second system is missing KB3000850

How to fix this powershell ParserError?

I am trying to create a powershell script (version 2.0) to send inline images, as explained here. But something does not seem to work, or is maybe outdated or incorrect.
The following is a complete test script
$msg = new-object Net.Mail.MailMessage
$image = "testImage.png"
$imageFull = "D:\Testing\testImage.png"
$attachment = New-Object System.Net.Mail.Attachment –ArgumentList $imageFull
$body=#"
<html>
<body>
<img src="cid:$image">
</body>
</html>
"#
which only uses an example image, and creates the following error:
The string starting:
At D:\Testing\Data\Powershell\LoadRunner\LRtestError.ps1:14 char:1
+ <<<< "#
is missing the terminator: ".
At D:\Testing\Data\Powershell\LoadRunner\LRtestError.ps1:16 char:1
+ <<<<
+ CategoryInfo : ParserError: (#
:String) [], ParseException
+ FullyQualifiedErrorId : TerminatorExpectedAtEndOfString
What is going on? Why is this error created? How to fix it?
NOTE:
If you comment out the System.Net.Mail.Attachment line, no error is created!!
Used OS: Windows Server 2008 R2 Standard (64-bit)
Full version table:
$psversiontable:
Name Value
---- -----
CLRVersion 2.0.50727.5485
BuildVersion 6.1.7601.17514
PSVersion 2.0
WSManStackVersion 2.0
PSCompatibleVersions {1.0, 2.0}
SerializationVersion 1.1.0.1
PSRemotingProtocolVersion 2.1
Make sure that #" are the first characters, and "# are last characters on the line. And that assigning the variable has it's own line $body=#". The code runs fine for me.
More information about these "Here-Strings" can be found here
$msg = new-object Net.Mail.MailMessage
$image = "testImage.png"
$imageFull = "D:\Testing\testImage.png"
$attachment = New-Object System.Net.Mail.Attachment –ArgumentList $imageFull
$body=#"
<html>
<body>
<img src="cid:$image">
</body>
</html>
"#

How use system.tuple in powershell?

Just for curiosity, it's not a 'I must have it', but how declare a tuple using system.tuple class in powershell?
I'm using powershell.exe.config to load framework 4.0 but I'm not able to create a tuple.
Trying this:
PS C:\ps1> $a = [System.Tuple``2]::Create( "pino", 34)
Chiamata al metodo non riuscita. [System.Tuple`2] non contiene un metodo denominato 'Create'.
In riga:1 car:31
+ $a = [System.Tuple``2]::Create <<<< ( "pino", 34)
+ CategoryInfo : InvalidOperation: (Create:String) [], RuntimeException
+ FullyQualifiedErrorId : MethodNotFound
sorry for Italian sample...
Thank you for help.
EDIT:
if i try:
PS C:\ps1> $a = [System.Tuple]::Create(34,"pino")
Impossibile trovare un overload per "Create" e il numero di argomenti: "2".
In riga:1 car:28
+ $a = [System.Tuple]::Create <<<< (34,"pino")
+ CategoryInfo : NotSpecified: (:) [], MethodException
+ FullyQualifiedErrorId : MethodCountCouldNotFindBest
Here is a way
PS> $a = New-Object 'Tuple[string,int]'("Jack", 78)
PS> $a
Item1 Item2
----- -----
Jack 78
Another one
PS> $dpt = New-Object 'Tuple[string,string,int]'("Cantal", "Aurillac", 15)
PS> $dpt.Item2
Aurillac
------EDIT------
Recall
to see which CLR you are using, just use $PSVersionTable
PS C:\> $PSVersionTable
Name Value
---- -----
CLRVersion 2.0.50727.4959
BuildVersion 6.1.7600.16385
PSVersion 2.0
WSManStackVersion 2.0
PSCompatibleVersions {1.0, 2.0}
SerializationVersion 1.1.0.1
PSRemotingProtocolVersion 2.1
if you want PowerShell to start using CLR 4.0 you have to put the file powershell.exe.config in the folder $PSHOME (C:\Windows\System32\WindowsPowerShell\v1.0)
powershell.exe.config :
<?xml version="1.0"?>
<configuration>
<startup useLegacyV2RuntimeActivationPolicy="true">
<supportedRuntime version="v4.0.30319"/>
<supportedRuntime version="v2.0.50727"/>
</startup>
</configuration>
Result :
PS C:\Users\JPB> $PSVersionTable
Name Value
---- -----
PSVersion 2.0
PSCompatibleVersions {1.0, 2.0}
BuildVersion 6.1.7600.16385
PSRemotingProtocolVersion 2.1
WSManStackVersion 2.0
CLRVersion 4.0.30319.225
SerializationVersion 1.1.0.1