How to use a PowerShell variable as command parameter? - variables

I'm trying to use a variable as a command's parameter but can't quite figure it out. Let's say MyCommand will accept two parameters: option1 and option2 and they accept boolean values. How would I use $newVar to substitute option 1 or 2? For example:
$newVar = "option1"
MyCommand -$newVar:$true
I keep getting something along the lines of 'A positional parameter cannot be found that accepts argument '-System.String option1'.
More Specifically:
Here, the CSV file is an output of a different policy. The loop goes through each property in the file and sets that value in my policy asdf; so -$_.name:$_.value should substitute as -AllowBluetooth:true.
Import-Csv $file | foreach-object {
$_.psobject.properties | where-object {
# for testing I'm limiting this to 'AllowBluetooth' option
if($_.name -eq "AllowBluetooth"){
Set-ActiveSyncMailboxPolicy -Identity "asdf" -$_.name:$_.value
}}
}

Typically to use a variable to populate cmdlet parameters, you'd use a hash table variable, and splat it, using #
$newVar = #{option1 = $true}
mycommand #newVar
Added example:
$AS_policy1 = #{
Identity = "asdf"
AllowBluetooth = $true
}
Set-ActiveSyncMailboxPolicy #AS_policy1

See if this works for you:
iex "MyCommand -$($newVar):$true"

I had the same Problem and just found out how to resolve it. Solution is to use invoke-Expression: invoke-Expression $mycmd
This uses the $mycmd-string, replaces variables and executes it as cmdlet with given parameters

Nowadays, If you don't mind evaluating strings as commands, you may use Invoke-Expression:
$mycmd = "MyCommand -$($newVar):$true"
Invoke-Expression $mycmd

I would try with:
$mycmd = "MyCommand -$($newVar):$true"
& $mycmd
result
Can't work because the ampersand operator just execute single commands without prameters, or script blocks.

Related

How to add value comma-separated parameter calling SQL query using SQLCMD via Powershell

I'm writing a PowerShell script that makes a call with SQLCMD to execute a .sql file and output a CSV file. In SQLCMD command, I want to pass a parameter back to query that includes a value of comma-separated list so I can use in an 'IN' statement.
select a, b, c, d
from dbtbl (nolock)
where client_id in ($(clients))
The SQLCMD command works if I assign $client_id to a singular value i.e. '000_abc' but does not work if I assign the variable as an array. i.e. '000_abc','000_def', '000_ghi'
# Input variables
$SQLSourceFolder = "V:\PS\queries\"
$FolderFile = "V:\PS\Myoutput.csv"
$TaxCode = "MY*script*.sql"
$qtr = "'1'"
$year = "'2019'"
#Works Fine. Only one client filtered in SQL query where clause
$client_id = "'000_abc'"
#Doesn't Work. Multiple clients filtered in SQL query where clause with IN statement.
# $client_id = "'000_abc','000_def', '000_ghi'"
# Find all files matching $TaxCode filter in the folder specified
Get-ChildItem -Path $SQLSourceFolder -Filter $TaxCode | ForEach-Object {
cls
Start-Process "D:\Program Files\Microsoft SQL Server\Client SDK\ODBC\110\Tools\Binn\SQLCMD.EXE" -ArgumentList #("-S","tcp:XXXXXXXXXXXXXX,1433", "-d" ,"XXX", "-U", "XXXXXXXX", "-P" ,"XXXXXXXXXX", " -v", " qtr = $qtr", " yr = $year", " clients = $client_id", " -W ", "-s", "~", "-i", "$($_.FullName)", "-o", "$FolderFile")
}
The expected result would be to pass multi-value variable to sql query where parameter is used in where clause with IN statement.
How come you're using sqlcmd.exe instead of Invoke-SqlCmd or, better yet, Invoke-SqlCmd2?
Quick context: Invoke-SqlCmd2 is a community drop-in replacement for Invoke-SqlCmd which addresses a few issues. It's widely considered the best solution for querying MS SQL from PS. Relevant: Install-Module Invoke-SqlCmd2, https://github.com/sqlcollaborative/Invoke-SqlCmd2
As you are discovering, passing arguments in to native applications is surprisingly difficult. It's always better to use PS commands where possible, in my experience.
Let me know if there's a good reason not to use Invoke-SqlCmd2 and I'll see what I can do to mock this for you, but it's a non-trivial effort on my part, so I do encourage you to just follow normal practice!

run powershell in VBA access

I need to change a string in multiple text files
I have written the script below in ACCESS VBA but the error is TYPE MISMATCH
Dim str As String
str = "N=maher"
Call Shell("c:\windows\system32\powershell.exe" - Command("get-content -Path e:\temptest.txt") - Replace(str, "maher", "ali"))
The syntax for calling PowerShell is way off. Suggestion: get it working from the command line yourself first, and then run from Access (an odd choice: it just makes this more complicated).
A PowerShell script to do this (.ps1 file) would need to contain something like:
Get-Content -Path "E:\temptest.txt" | ForEach-Object { $_ -Replace 'maher', 'ali' } | do-something-with-the-updated-content
You need to define:
What you are replacing (you pass N=maher in but then hard code two strings for Replace.
What do to with the strings after doing the replacement (Get-Content only reads files).

TCL: tcl command execute by variable

I am a beginner with tcl.
I am trying to use primetime execute command, but it can't accept variable.
For example:
set var "get_timing_paths -rise_from A -rise_to B"
set path0001 [$var]
But it doesn't work.
The things I want to do is
set path0001 [get_timing_paths -rise_from A -rise_to B]
but I need to seperate it.
Thank you for your answer.
If you're using Tcl/Tk 8.5 or newer, it'd be better to use the list expansion operator {*} instead of eval:
set var "get_timing_paths -rise_from A -rise_to B"
set path0001 [{*}$var]
It's a bit faster and safer.
Just add eval while calling the command.
set path0001 [eval $var]
Reference : eval

Powershell piping to variable and write-host at the same time

Hello all and thanks for your time in advance;
I'm running into a slight issue.
I'm running a command and piping it into a variable so i can manipulate the output.
$variable = some command
this normally works fine but doesn't output what's happening to the screen, which is fine most of the time. However occasionally this command requires some user input (like yes or no or skip for example), and since it's not actually piping anything to the command window, it just sits there hanging instead of prompting the user. If you know what to expect you can hit y or n or s and it'll proceed normally.
Is there anyway to run the command so that the output is piped to a variable AND appears on screen? I've already tried:
($variable = some command)
I've also tried:
write-host ($variable = some command)
But neither work. Note that the command running isn't a native windows or shell command and I cannot just run it twice in a row.
To clarify (because i probably wasn't clear)
I've also tried :
$variable = some command : Out-host
and
$variable = some command | out-default
with all their parameters, But the "prompt" from the command (to write y, n, s) doesn't show up.
Being able to pass S automatically would also be acceptable.
Sounds like you need Tee-Object. Example:
some command | Tee-Object -Variable MyVariable
This should pass everything from the command down the pipe, as well as store all output from the command in the $MyVariable variable for you.
You need to give some specific example that doesn't work. I tried this and it works:
function test { $c = read-host "Say something"; $c }
$x = test
I still see "Say something". read-host does not output to standard output so your problem is surprising. Even this works:
read-host "Say something" *> out
=== EDIT ===
Since this is interaction with cmd.exe you have two options AFAIK. First, test command:
test.cmd
#echo off
set /p something="Say something: "
echo %something%
This doesn't work as you said: $x= ./test.cmd
To make it work:
a) Replace above command with: "Say something:"; $x= ./test.cmd. This is obviously not ideal in general scenario as you might not know in advance what the *.cmd will ask. But when you do know its very easy.
b) Try this:
Start-transcript test_out;
./test.cmd;
Stop-transcript;
gc .\test_out | sls 'test.cmd' -Context 0,1 | select -Last 1 | set y
rm test_out
$z = ($y -split "`n").Trim()
After this $z variable contains: Say something: something. This could be good general solution that you could convert to function:
$z = Get-CmdOutput test.cmd
Details of text parsing might be slightly different in general case - I assumed here that only 1 question is asked and answer is on the same line but in any case with some work you will be able to get everything cmd.exe script outputed in general case:
=== EDIT 2 ===
This might be a better general extraction:
$a = gi test_out; rm test_out
$z = $a | select -Index 14,($a.count-5)
$z
$variable = ""
some command | % {$variable += $_;"$_"}
This executes the command, and each line of output is both added to $variable and printed to the console.

How to pass boolean values to a PowerShell script from a command prompt

I have to invoke a PowerShell script from a batch file. One of the arguments to the script is a boolean value:
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -NoProfile -File .\RunScript.ps1 -Turn 1 -Unify $false
The command fails with the following error:
Cannot process argument transformation on parameter 'Unify'. Cannot convert value "System.String" to type "System.Boolean", parameters of this type only accept booleans or numbers, use $true, $false, 1 or 0 instead.
At line:0 char:1
+ <<<< <br/>
+ CategoryInfo : InvalidData: (:) [RunScript.ps1], ParentContainsErrorRecordException <br/>
+ FullyQualifiedErrorId : ParameterArgumentTransformationError,RunScript.ps1
As of now I am using a string to boolean conversion inside my script. But how can I pass boolean arguments to PowerShell?
A more clear usage might be to use switch parameters instead. Then, just the existence of the Unify parameter would mean it was set.
Like so:
param (
[int] $Turn,
[switch] $Unify
)
It appears that powershell.exe does not fully evaluate script arguments when the -File parameter is used. In particular, the $false argument is being treated as a string value, in a similar way to the example below:
PS> function f( [bool]$b ) { $b }; f -b '$false'
f : Cannot process argument transformation on parameter 'b'. Cannot convert value
"System.String" to type "System.Boolean", parameters of this type only accept
booleans or numbers, use $true, $false, 1 or 0 instead.
At line:1 char:36
+ function f( [bool]$b ) { $b }; f -b <<<< '$false'
+ CategoryInfo : InvalidData: (:) [f], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : ParameterArgumentTransformationError,f
Instead of using -File you could try -Command, which will evaluate the call as script:
CMD> powershell.exe -NoProfile -Command .\RunScript.ps1 -Turn 1 -Unify $false
Turn: 1
Unify: False
As David suggests, using a switch argument would also be more idiomatic, simplifying the call by removing the need to pass a boolean value explicitly:
CMD> powershell.exe -NoProfile -File .\RunScript.ps1 -Turn 1 -Unify
Turn: 1
Unify: True
Try setting the type of your parameter to [bool]:
param
(
[int]$Turn = 0
[bool]$Unity = $false
)
switch ($Unity)
{
$true { "That was true."; break }
default { "Whatever it was, it wasn't true."; break }
}
This example defaults $Unity to $false if no input is provided.
Usage
.\RunScript.ps1 -Turn 1 -Unity $false
This is an older question, but there is actually an answer to this in the PowerShell documentation. I had the same problem, and for once RTFM actually solved it. Almost.
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_powershell_exe
Documentation for the -File parameter states that
"In rare cases, you might need to provide a Boolean value for a switch parameter. To provide a Boolean value for a switch parameter in the value of the File parameter, enclose the parameter name and value in curly braces, such as the following: -File .\Get-Script.ps1 {-All:$False}"
I had to write it like this:
PowerShell.Exe -File MyFile.ps1 {-SomeBoolParameter:False}
So no '$' before the true/false statement, and that worked for me, on PowerShell 4.0
I think, best way to use/set boolean value as parameter is to use in your PS script it like this:
Param(
[Parameter(Mandatory=$false)][ValidateSet("true", "false")][string]$deployApp="false"
)
$deployAppBool = $false
switch($deployPmCmParse.ToLower()) {
"true" { $deployAppBool = $true }
default { $deployAppBool = $false }
}
So now you can use it like this:
.\myApp.ps1 -deployAppBool True
.\myApp.ps1 -deployAppBool TRUE
.\myApp.ps1 -deployAppBool true
.\myApp.ps1 -deployAppBool "true"
.\myApp.ps1 -deployAppBool false
#and etc...
So in arguments from cmd you can pass boolean value as simple string :).
Running powershell scripts on linux from bash gives the same problem. Solved it almost the same as LarsWA's answer:
Working:
pwsh -f ./test.ps1 -bool:true
Not working:
pwsh -f ./test.ps1 -bool=1
pwsh -f ./test.ps1 -bool=true
pwsh -f ./test.ps1 -bool true
pwsh -f ./test.ps1 {-bool=true}
pwsh -f ./test.ps1 -bool=$true
pwsh -f ./test.ps1 -bool=\$true
pwsh -f ./test.ps1 -bool 1
pwsh -f ./test.ps1 -bool:1
To summarize and complement the existing answers, as of Windows PowerShell v5.1 / PowerShell Core 7.0.0-preview.4:
David Mohundro's answer rightfully points that instead of [bool] parameters you should use [switch] parameters in PowerShell, where the presence vs. absence of the switch name (-Unify specified vs. not specified) implies its value, which makes the original problem go away.
However, on occasion you may still need to pass the switch value explicitly, particularly if you're constructing a command line programmatically:
In PowerShell Core, the original problem (described in Emperor XLII's answer) has been fixed.
That is, to pass $true explicitly to a [switch] parameter named -Unify you can now write:
pwsh -File .\RunScript.ps1 -Unify:$true # !! ":" separates name and value, no space
The following values can be used: $false, false, $true, true, but note that passing 0 or 1 does not work.
Note how the switch name is separated from the value with : and there must be no whitespace between the two.
Note: If you declare a [bool] parameter instead of a [switch] (which you generally shouldn't), you must use the same syntax; even though -Unify $false should work, it currently doesn't - see this GitHub issue.
In Windows PowerShell, the original problem persists, and - given that Windows PowerShell is no longer actively developed - is unlikely to get fixed.
The workaround suggested in LarsWA's answer - even though it is based on the official help topic as of this writing - does not work in v5.1
This GitHub issue asks for the documentation to be corrected and also provides a test command that shows the ineffectiveness of the workaround.
Using -Command instead of -File is the only effective workaround:
:: # From cmd.exe
powershell -Command "& .\RunScript.ps1 -Unify:$true"
With -Command you're effectively passing a piece of PowerShell code, which is then evaluated as usual - and inside PowerShell passing $true and $false works (but not true and false, as now also accepted with -File).
Caveats:
Using -Command can result in additional interpretation of your arguments, such as if they contain $ chars. (with -File, arguments are literals).
Using -Command can result in a different exit code.
For details, see this answer and this answer.
In PowerShell, boolean parameters can be declared by mentioning their type before their variable.
function GetWeb() {
param([bool] $includeTags)
........
........
}
You can assign value by passing $true | $false
GetWeb -includeTags $true
I had something similar when passing a script to a function with invoke-command. I ran the command in single quotes instead of double quotes, because it then becomes a string literal. 'Set-Mailbox $sourceUser -LitigationHoldEnabled $false -ElcProcessingDisabled $true';
Based on my test, a default value specification does not work for a parameter that is expected to be a boolean in the Function.
You can use the [switch] type or if you really want to use boolean, you should specify default value at the start of the function like below:
Function nullRules {
Param
(
[Parameter(Mandatory=$false)] $boolWins
)
if ([DBNull]::Value.Equals($boolWins)) {$boolWins=$false}
....
....
}
You can also use 0 for False or 1 for True. It actually suggests that in the error message:
Cannot process argument transformation on parameter 'Unify'. Cannot convert value "System.String" to type "System.Boolean", parameters of this type only accept booleans or numbers, use $true, $false, 1 or 0 instead.
For more info, check out this MSDN article on Boolean Values and Operators.