Compare select-string piped result against a string - powershell

I want to compare grep a like Select-String result against a string and return a Boolean true or false, but I can't match the right syntax when I put everything in the if/else expressions.
The error output that I get is:
At line:1 char:102
+ ... Object {$_ | Select-String 1 packages found.}) -eq 1 packages found.) ...
+ ~~~~~~~~ Unexpected token 'packages' in expression or statement. At line:1
char:102
+ ... Object {$_ | Select-String 1 packages found.}) -eq 1 packages found.) ...
+ ~~~~~~~~ Missing closing ')' after expression in 'if' statement. At line:1
char:117
+ ... $_ | Select-String 1 packages found.}) -eq 1 packages found.) { echo ...
+ ~ Unexpected token ')' in expression or statement. At line:1 char:184
+ ... rometheus-wmi-exporter is already installed, skipping. } else { c:/pr ...
+ ~~~~ Unexpected token 'else' in expression or statement.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : UnexpectedToken
If I run the contents of the first expression I get the result as I expect it, but I fail to return a Boolean true or false when I put it in the expression part of the if.
powershell -NoProfile -ExecutionPolicy unrestricted -Command --% "if ((choco list prometheus-wmi-exporter | Where-Object {$_ | Select-String "1 packages found."}) -eq "1 packages found.") { echo "prometheus-wmi-ex
porter is already installed, skipping." } else { c:/programdata/chocolatey/bin/choco.exe install --force -y prometheus-wmi-exporter.install }"
My end goal is if I get a match to return true, else to return false and execute the false statement.

your command doesn't check what you expect, it just retuns if such a package exists,
not if it is installed -local
the question is tagged [powershell] but you invoke powershell? Is this supposed to run from a batch? If so why not just use clist.exe (shortcut for choco list) and find to check?
clist -local|find /i "prometheus-wmi-exporter" &&(echo installed)||(echo not installed)
the command is overly complex, an if with choco output checked with a -(not)match should suffice.
if((clist -local) -match 'prometheus-wmi-exporter'){"installed"}else{"not installed"}
before wrapping the command test it directly

Try rewriting like this:
powershell -NoProfile -Command "if (choco prometheus-wmi-exporter | Select-String '1 packages found.') { echo 'prometheus-wmi-exporter is already installed, skipping.' } else { c:/programdata/chocolatey/bin/choco.exe install --force -y prometheus-wmi-exporter.install }"

Related

Powershell - An empty pipe element is not allowed problem

I Tried running this in powershell
cd "c:thetesttun2" ; if ($?) { nvcc thetestrun2.cu -o thetestrun2 } ; if ($?) { .\thetestrun2 } | Out-File "C:\thetesttun2\hellow.txt"
and this error keeps coming up
An empty pipe element is not allowed. + CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException + FullyQualifiedErrorId : EmptyPipeElement
Please help I am new to powershell
Please give me some code to run on my machine
As hinted in comments, a pipeline statement cannot begin with a control flow structure like if(...){...} - the first element has to start with either a value expression or a command element.
There's a couple of options for solving this. If you simply want the output from the eventual invocation of the program, move | Out-File into the if body:
cd "c:thetesttun2"
if ($?) { nvcc thetestrun2.cu -o thetestrun2 }
if ($?) { .\thetestrun2 | Out-File "C:\thetesttun2\hellow.txt" }
If you also want to stream the output from the compilation to the file, wrap the whole thing in a scriptblock {...} (thus turning the whole thing into a command element) and invoke with the & call operator:
cd "c:thetesttun2"
& {
if ($?) { nvcc thetestrun2.cu -o thetestrun2 }
if ($?) { .\thetestrun2 }
} | Out-File "C:\thetesttun2\hellow.txt"
Finally, you can also wrap the if statements in the $(...) subexpression operator or the #(...) array subexpression operator, thus turning the whole thing into a value expression:
cd "c:thetesttun2"
#(
if ($?) { nvcc thetestrun2.cu -o thetestrun2 }
if ($?) { .\thetestrun2 }
) | Out-File "C:\thetesttun2\hellow.txt"
... but beware that this will block while executing the statements, and output won't start streaming until the subexpression has been fully evaluated, thus incurring higher memory allocations for the process - which is why I suggest the scriptblock approach detailed above instead :)

Setup deployment group agent with powershell failed

I try to run the script provided in “deployment group” section on my Win7 VM (what I do is just “copy\paste\run”).
$ErrorActionPreference="Stop";
If(-NOT ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent() ).IsInRole( [Security.Principal.WindowsBuiltInRole] “Administrator”)){ throw "Run command in an administrator PowerShell prompt"};
If($PSVersionTable.PSVersion -lt (New-Object System.Version("3.0"))){ throw "The minimum version of Windows PowerShell that is required by the script (3.0) does not match the currently running version of Windows PowerShell." };
If(-NOT (Test-Path $env:SystemDrive\'azagent')){mkdir $env:SystemDrive\'azagent'};
cd $env:SystemDrive\'azagent';
for($i=1; $i -lt 100; $i++){$destFolder="A"+$i.ToString();
if(-NOT (Test-Path ($destFolder))){mkdir $destFolder;cd $destFolder;break;}};
$agentZip="$PWD\agent.zip";
$DefaultProxy=[System.Net.WebRequest]::DefaultWebProxy;$securityProtocol=#();$securityProtocol+=[Net.ServicePointManager]::SecurityProtocol;
$securityProtocol+=[Net.SecurityProtocolType]::Tls12;[Net.ServicePointManager]::SecurityProtocol=$securityProtocol;
$WebClient=New-Object Net.WebClient;
$Uri='https://vstsagentpackage.azureedge.net/agent/2.204.0/vsts-agent-win-x64-2.204.0.zip';
if($DefaultProxy -and (-not $DefaultProxy.IsBypassed($Uri))){$WebClient.Proxy= New-Object Net.WebProxy($DefaultProxy.GetProxy($Uri).OriginalString, $True);};
$WebClient.DownloadFile($Uri, $agentZip);
Add-Type -AssemblyName System.IO.Compression.FileSystem;
[System.IO.Compression.ZipFile]::ExtractToDirectory( $agentZip, "$PWD");
.\config.cmd --deploymentgroup --deploymentgroupname "MY_GROUP_NAME" --agent $env:COMPUTERNAME --runasservice --work '_work' --url 'https://dev.azure.com/MY_ORG_NAME/' --projectname 'MY_PROJ_NAME';
Remove-Item $agentZip;
And error occurs:
em $agentZip;
At line:1 char:179
+ ... Current() ).IsInRole( [Security.Principal.WindowsBuiltInRole] “Adminis ...
+ ~
Missing ')' in method call.
At line:1 char:180
+ ... nRole( [Security.Principal.WindowsBuiltInRole] “Administrator?){ throw ...
+ ~~~~~~~~~~~~~~
Unexpected token '“Administrator?' in expression or statement.
At line:1 char:180
+ ... nRole( [Security.Principal.WindowsBuiltInRole] “Administrator?){ throw ...
+ ~~~~~~~~~~~~~~
Missing closing ')' after expression in 'If' statement.
At line:1 char:194
+ ... Role( [Security.Principal.WindowsBuiltInRole] “Administrator?){ throw ...
+ ~
Unexpected token ')' in expression or statement.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : MissingEndParenthesisInMethodCall
Here is the info of powershell version:
Any suggestion is appreciated.
As mentioned in the question comments, the issue stems around faulty quotation marks in the provided registration script.
It seems to only affect more modern Windows/PowerShell versions, so it hasn't been addressed by Microsoft with any priority yet. For now, the workaround is to find and replace.
If you paste the script into a text editor, search for “Administrator” and replace with "Administrator".
If you paste the script into (a modern) PowerShell prompt directly, the faulty characters will be stripped and you will need to manually add them:

String comparison not working in powershell

I am trying an if else condition in powershell using string comparison. I tried as per documentation using -eq operator. But getting below error. Here "Build.Reason" is a predefined variable. Not sure why its looking for cmdlet name for variable.
Write-Host "$(Build.Reason)"
if ($(Build.Reason) -eq "Manual" ) {
$temp = "https://url/api/qualitygates/project_status?&pullRequest=$(Build.Reason)"
Write-Host "Manual"
} else {
Write-Host "CI"
}
Error
"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -NoLogo -NoProfile -NonInteractive -ExecutionPolicy Unrestricted -Command ". 'D:\a\_temp\d7af16d6-ce3e-4dec-a636-9447962fdac4.ps1'"
Manual
Manual : The term 'Manual' 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 D:\a\_temp\d7af16d6-ce3e-4dec-a636-9447962fdac4.ps1:7 char:5
+ if (Manual -eq "Manual" ) {
+ ~~~~~~
+ CategoryInfo : ObjectNotFound: (Manual:String) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : CommandNotFoundException
It looks like $(Build.Reason) is a macro-style value provide by a CI system (it is not a PowerShell construct), which is expanded to become a literal part of the code before PowerShell sees it.
Therefore, if this value is to be treated as a string in the resulting PowerShell code, you need to quote it; e.g.:
if ("$(Build.Reason)" -eq "Manual") { # ...
Note that if there's a chance that $(Build.Reason) expands to a value with embedded " characters, they would have to be escaped as `". Similarly, if the value contains embedded $ chars., single-quoting should be used, which may then require escaping embedded single quotes as ''.
If this escaping cannot be performed at the source, you can use a verbatim here-string:
if (#'
$(Build.Reason)
'# -eq 'Manual') { # ...
Important: The closing '# must always be at the very beginning of the line.

using powershell invoke-expression to run code output

I have been doing a lot of reading on invoke-expression (also known as iex) and I'm having trouble getting it to work for me.
My understanding is, it will run any powershell code you give to it. However, when I run my tests on it, it does not run the code.
Example:
## testcode.ps1
$myvar = "i am here"
if ($myvar -ne $null) {
"($myvar) variable is Full"
} else {
"($myvar) variable is Empty"
}
Now, if I cat(gc) this file and I pass it to iex, it outputs a bunch of errors. Same thing happens when I save the code into a variable and then feed the variable to iex. Neither works.
Despite the fact that I've tried numerous examples, I feel there's something minor I'm doing wrong that I'm hoping someone can point out for me.
I'm new to Windows scripting, so please bear with me. These are the results of the tests I performed:
First Test:
PS C:\Users\J> gc C:\Users\J\testcode.ps1 | iex
Invoke-Expression : Cannot bind argument to parameter 'Command' because it is an empty string.
At line:1 char:31
+ cat C:\Users\J\testcode.ps1 | iex
+ ~~~
+ CategoryInfo : InvalidData: (:PSObject) [Invoke-Expression], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorEmptyStringNotAllowed,Microsoft.PowerShell.Commands.InvokeExpressionCommand
iex : At line:1 char:23
+ if ($myvar -ne $null) {
+ ~
Missing closing '}' in statement block or type definition.
At line:1 char:31
+ cat C:\Users\J\testcode.ps1 | iex
+ ~~~
+ CategoryInfo : ParserError: (:) [Invoke-Expression], ParseException
+ FullyQualifiedErrorId : MissingEndCurlyBrace,Microsoft.PowerShell.Commands.InvokeExpressionCommand
Second Test:
PS C:\Users\J> $scriptBlock = gc C:\Users\J\testcode.ps1
PS C:\Users\J>
PS C:\Users\J> iex -Command "$scriptBlock"
iex : At line:1 char:23
+ $myvar = "i am here" if ($myvar -ne $null) { "($myvar) variable ...
+ ~~
Unexpected token 'if' in expression or statement.
At line:1 char:1
+ iex -Command "$scriptBlock"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ParserError: (:) [Invoke-Expression], ParseException
+ FullyQualifiedErrorId : UnexpectedToken,Microsoft.PowerShell.Commands.InvokeExpressionCommand
PS C:\Users\J>
I'm aware that I can just run the file containing the code. However, I need help figuring out how iex works and what it is I'm doing wrong.
Please kindly advise.
First things first:
Invoke-Expression should generally be avoided and used only as a last resort, due to its security risks. In short: avoid it, if possible, given that superior alternatives are usually available. If there truly is no alternative, only ever use it on input you either provided yourself or fully trust - see this answer.
For the record: in the case at hand, the superior alternative is to directly invoke the script file:
# Prepend `& `, if the script file path is quoted or references a variable.
C:\Users\J\testcode.ps1
Invoke-Expression (iex) accepts multiple strings via the pipeline, and evaluates each individually, as a self-contained script.
Therefore, you must provide the contents of your script as a whole, as a single string, which is what Get-Content's (gc's) -Raw switch does[1]:
Get-Content -Raw C:\Users\J\testcode.ps1 | Invoke-Expression
Alternatively, pass the script-file contents as an argument:
Invoke-Expression (Get-Content -Raw C:\Users\J\testcode.ps1)
Note that passing the string to evaluate as an argument truly only accepts a single string, so the command would fail without -Raw.
[1] By default, the Get-Content cmdlet reads a file line by line, passing each line through the pipeline as it is being read.
$myvar = "I'm Here"
#Using Invoke-Expression - Accepts a STRING as Input
$SBCode = 'if ($Null -ne $myvar) {"($myvar) variable is Full"}' +
'else {"`$myvar variable is Empty"}'
Clear-Host
"Before Invoke-Expression `$myvar = $myvar"
$Result = Invoke-Expression $SBCode
"Invoke-Expression Returns: $Result"
#Using Invoke-Command - Accepts Script Block as Input
$SBCode = {
if ($myvar -ne $null) {
"($myvar) variable is Full"
}
else {
"`$myvar variable is Empty"
}
} #End $SBCode Script Block
"Before Invoke-Command `$myvar = $myvar"
$Result = Invoke-Command -ScriptBlock $SBCode
"Invoke-Command Returns: $Result"
Results:
Before Invoke-Expression $myvar = I'm Here
Invoke-Expression Returns: (I'm Here) variable is Full
Before Invoke-Command $myvar = I'm Here
Invoke-Command Returns: (I'm Here) variable is Full
# After changing $MyVar = $Null
Before Invoke-Expression $myvar =
Invoke-Expression Returns: $myvar variable is Empty
Before Invoke-Command $myvar =
Invoke-Command Returns: $myvar variable is Empty
HTH
You can use out-string to convert output into string.
cat C:\Users\J\testcode.ps1 | out-string | Invoke-Expression

How to run Powershell script in VS Code using Powershell Integrated Console

I have this little script, which works fine in PowerShell (outside of VS Code):
$a = #{Portfolio = "CALoan"; Folder = "S:\Data\{yymmdd}"; Filename = "LN{yymmdd}.txt"}
$l = #($a)
$l | ForEach-Object -Process {
$p = ($_.Folder + '\' + $_.Filename).Replace("{yymmdd}", "190911")
if (Test-Path $p) {
[pscustomobject] #{Portfolio = $_.Portfolio; Path = $p; CreateTime = (Get-ChildItem $p).CreationTime}
} else {
[pscustomobject] #{Portfolio = $_.Portfolio; Path = $p; CreateTime = "not found"}
}
} | Out-GridView
However, when viewing the script in the VSCode editor, if I just right-click and choose Run Code (using the Code Runner extension), I get tons of errors like this:
PS C:\Users\me> $l | ForEach-Object -Process {
Missing closing '}' in statement block or type definition.
At line:0 char:0
PS C:\Users\me> $p = ($_.Folder + '\' + $_.Filename).Replace("{yymmdd}", "190911")
PS C:\Users\me> if (Test-Path $p) {
Missing closing '}' in statement block or type definition.
At line:0 char:0
PS C:\Users\me> [pscustomobject] #{Portfolio = $_.Portfolio; Path = $p; CreateTime = (Get-ChildItem $p).CreationTime}
Portfolio Path CreateTime
--------- ---- ----------
\ {2/28/2019 12:41:46 PM, 2/20/2019 12:32:15 PM, 1/24/2019 3:54:50 PM, 3/15/2019 1:46:40 PM...}
PS C:\Users\me> } else {
At line:1 char:1
+ } else {
+ ~
Unexpected token '}' in expression or statement.
At line:1 char:8
+ } else {
+ ~
Missing closing '}' in statement block or type definition.
PS C:\Users\me> [pscustomobject] #{Portfolio = $_.Portfolio; Path = $p; CreateTime = "not found"}
Portfolio Path CreateTime
--------- ---- ----------
\ not found
PS C:\Users\me> }
At line:1 char:1
+ }
+ ~
Unexpected token '}' in expression or statement.
PS C:\Users\me> } | Out-GridView
At line:1 char:1
+ } | Out-GridView
+ ~
Unexpected token '}' in expression or statement.
At line:1 char:3
+ } | Out-GridView
+ ~
An empty pipe element is not allowed.
PS C:\Users\me>
It's as if the integrated terminal is executing one line at a time rather than sending the whole script to PowerShell. What is the right way to do this?
BTW If I start a new PowerShell terminal within VS Code, it works as expected (also using Code Runner). So, what's up with the PowerShell Integrated Console and Code Runner?
I can't speak to the Code Runner extension, but you can bypass the problem by installing the PowerShell extension, which is invaluable for both editing and running PowerShell code in Visual Studio Code.
It allows you to run selected code reliably and faster (because no intermediate script file and external PowerShell process is involved - see below) by:
either pressing F8
or right-clicking the selected text and clicking Run Selection.
Caveat:
By default, code you run via the PowerShell extension executes in the same PowerShell session, so that subsequent invocations can be affected by previous ones; e.g., if you highlight a line containing (++$i) and run it repeatedly, the value of $i keeps incrementing.
Turning on setting Create Temporary Integrated Console (via File > Preferences > Settings or Ctrl+,) can be used to change that, so that every invocation creates a new, temporary session to run in.