How to get values from workflow parallel code block? - powershell

I'm trying to run two Invoke-Sqlcmd in parallel and then wait all the results.
$server1 = '...'
$server2 = '...'
workflow work {
parallel {
$r1 = Invoke-Sqlcmd -ServerInstance $server1 'select 1 a'
$r2 = Invoke-Sqlcmd -ServerInstance $server2 'select 2 a'
}
}
work
# do something with $r1 and $r2. How to access the variables here?
How to pass $server1 and $server2 to the code block?
How to get $r1 and $r2 from the parallel block?

So pass in servers with param, and return a hashtable of both results.
$server1 = '...'
$server2 = '...'
workflow work {
param ($server1, $server2)
parallel {
#{r1 = Invoke-Sqlcmd -ServerInstance $server1 'select 1 a'}
#{r2 = Invoke-Sqlcmd -ServerInstance $server2 'select 2 a'}
}
}
$r = work $server1 $server2
$r.r1
$r.r2

Related

Powershell Invoke-Sqlcmd Use result in another query

I'm attempting to use a result returned from Invoke-Sqlcmd $ORDUNIQ as a variable in a second query. However the second $query2 returns 0 records. Substituting the variable for the actual string value '35973189' works fine.
I'm assuming that $ORDUNIQ.ORDUNIQ is the wrong way to use this?, although running $ORDUNIQ.ORDUNIQ on the command line does return '35973189' correctly
Here is my code
$RAWFiles = Get-ChildItem D:\Imports\Test\*.csv
$content = Import-Csv $RAWFiles | Where-Object 'Order Type' -eq 'B2B'
ForEach ($row in $content) {
$ORDNUMBER = $row.'OrderRef'
$SQLServer = "XXXXX-XXX"
$db1 = "XXXXXX"
$query1 = "SELECT ORDUNIQ FROM OEORDH WHERE ORDNUMBER = '$ORDNUMBER'"
$query2 = "SELECT OEORDD.ITEM FROM OEORDD WHERE ORDUNIQ = '$ORDUNIQ.ORDUNIQ'"
$ORDUNIQ = Invoke-Sqlcmd -ServerInstance $SQLServer -Database $db1 -Query $query1
$ORDDATA = Invoke-SQLcmd -ServerInstance $SQLServer -Database $db1 -Query $query2
}

How to pass variable value from a map defined outside invoke command and to be used after invoke command

I am writing a script in powershell where after login with User 1 on a system, it will switch to user 2 and then make a connection to database with this user. However, the dbinstance details, port No and Computer name to be passed in invoke command will be defined as a map before the 2nd invoke command i.e. when it will invoke the command to open powershell with 2nd user(db user). It is able to take userid in this case i.e. when to invoke the powershell connection with 2nd user, however it is not able to pass the values of dbinstance and port to next sqlcmd invoke. Below is the code for reference. In this code it works fine while getting $inputMap.UserNameP, however it fails in passing $inputMap.DBInstance,$inputMap.PortNo.
$UserName = 'User1'
$securekey = #'
securekey1
'# |ConvertTo-SecureString -AsPlainText -Force;
$concreds=New-Object System.Management.Automation.PSCredential -ArgumentList $UserName, $securekey;
Invoke-Command -Credential $concreds -ComputerName 'abc.domainname'-Authentication Credssp -ScriptBlock {
function checkFaultHighUtilization() {
$local:ExecStdOperatorOut=Invoke-Command -ScriptBlock {
$inputMap=#{"UserNameP"="User2";"DBInstance"="databaseinstancename";"PortNo"="portnumber";};
$securekey1 = "securekey1"
$finalresult = #()
$securekey2 = $securekey1 | ConvertTo-SecureString -AsPlainText -Force;
$concreds=New-Object System.Management.Automation.PSCredential -ArgumentList $inputMap.UserNameP, $securekey2;
Invoke-Command -Credential $concreds -ComputerName 'computername' -Authentication Credssp -ScriptBlock {
$var1=Invoke-Sqlcmd -query "
Begin
select * from db
End" -ServerInstance "$inputMap.DBInstance,$inputMap.PortNo"
##if (($var1.count) -gt 0) {
foreach($row in $var1){
$finalresult+=$row.a+':'+$row.b+':'+$row.c
echo $finalresult
}
}
}
$local:ExecStdOperatorRet=if($local:ExecStdOperatorOut) {0} else {1}
return $local:ExecStdOperatorRet,$local:ExecStdOperatorOut;
};
$ESExecReturn,$ESExecOutput=checkFaultHighUtilization
$ESExecOutput=($ESExecOutput | Out-String).Trim();
Write-output "ESExecOutput:";
Write-output $ESExecOutput;
Write-output ":ESExecOutput";Write-output $("ESExecError:" + $Error + ":ESExecError");
Write-output $("ESExecReturn:" + $ESExecReturn + ":ESExecReturn");
}
$scriptBlockOne = {
$variableA = "Hello World"
return $variableA
}
$scriptBlockTwo = {
param (
$inputString
)
Write-host $inputString
}
$invokeCommandReturn = Invoke-Command -ScriptBlock $scriptBlockOne
Invoke-Command -ScriptBlock $scriptBlockTwo -ArgumentList $invokeCommandReturn
You're trying to use expressions such as $inputMap.DBInstance as-is inside an expandable string ("..."), which is syntactically not supported.
To use expressions, you must enclose them in $(...), the subexpression operator.
See this answer for a comprehensive discussion of string interpolation in PowerShell.
Therefore:
# ...
$var1 = Invoke-Sqlcmd -Query "
Begin
select * from db
End" -ServerInstance "$($inputMap.DBInstance),$($inputMap.PortNo)" # Note the $()
# ...

How to process multiple columns from sql in powershell

I have this PowerShell script:
$QUERY = "SELECT name FROM sys.databases";
$Databases = invoke-sqlcmd -serverinstance "SQLInstanceName" -database "master" -Query $QUERY
foreach ($dbname in $Databases)
{
$dbname
}
Let's say I want the recovery model for the databases as below, how do I get them into PowerShell variables?
$QUERY = "SELECT name, recovery_model_desc FROM sys.databases";
May be you are looking for
$QUERY = "SELECT * from sys.databases";
$Databases = invoke-sqlcmd -serverinstance "SQLInstanceName" -database "master" -Query $QUERY
# This is just to print the individual value of column (name and recovery_model)
$Databases | ForEach {
Write-Host '----------------------------------------'
Write-Host 'Database :' $_.name
Write-Host 'Recovery model :' $_.recovery_model
Write-Host '----------------------------------------'
Write-Host
}
# This will give you name and recovery_model of database
$Databases | Select name, recovery_model

Code not being seen if I include it from a file

I'm writing some Powershell scripts to manage a SQL Server. When I create my SMO object, I do a test to see if I can list my databases. If so, then I assume I'm connected and call a function (via an included file) that has an Invoke-Sqlcmd that causes my database to disconnect or something.
However, if I run the invoke command directly in the script, it works fine.
Looking at the provided code, my output is as follows:
I'm connected
$SqlServer is not contactable
[System.Reflection.Assembly]::LoadWithPartialName('Microsoft.SqlServer.SMO') | Out-Null
$ErrorActionPreference = "Stop"
Import-Module 'sqlps' -DisableNameChecking #load all of SMO
$ScriptDirectory = Split-Path -Path $MyInvocation.MyCommand.Definition -
Parent
try {
("$ScriptDirectory\_HRbackup.ps1")
("$ScriptDirectory\_HRprinter.ps1")
("$ScriptDirectory\_HRbody.ps1")
} catch {
Write-Host "Error while loading supporting PowerShell Scripts"
}
$ServerList = $env:COMPUTERNAME
$SqlServer = New-Object ('Microsoft.SqlServer.Management.Smo.Server')
$ServerList # add server list
try {
$databases = $SqlServer.Databases
if ($databases.Count -gt 0) {
Write-Host "I am connected"
Backup-Html
} else {
$login = Get-Credential -Message 'Please prov#ide your SQL
Credentials'
$SqlServer.ConnectionContext.LoginSecure = $false
$SqlServer.ConnectionContext.Login = $login.UserName
$SqlServer.ConnectionContext.set_SecurePassword($login.Password)
$SqlServer.ConnectionContext.connect()
}
} catch {
$WarningPreference = 'continue'
Write-Warning "$SqlServer is not contactable"
#$SqlServer.ConnectionContext.Disconnect()
} finally {
$SqlServer.ConnectionContext.Disconnect()
}
Here is the content of Backup-Html:
$Query = "select top 5 a.server_name, a.database_name,
backup_finish_date, a.backup_size,
CASE a.[type] -- Let's decode the three main types of
backup here
WHEN 'D' THEN 'Full'
WHEN 'I' THEN 'Differential'
WHEN 'L' THEN 'Transaction Log'
ELSE a.[type]
END as BackupType
-- Build a path to the backup
,'\\' +
-- lets extract the server name out of the recorded
server and instance name
CASE
WHEN patindex('%\%',a.server_name) = 0 THEN
a.server_name
ELSE
substring(a.server_name,1,patindex('%\%',a.server_name)-1)
END
-- then get the drive and path and file information
+ '\' + replace(b.physical_device_name,':','$') AS
'\\Server\Drive\backup_path\backup_file'
from msdb.dbo.backupset a join msdb.dbo.backupmediafamily
b
on a.media_set_id = b.media_set_id
where a.database_name Like 'Easy%'
order by a.backup_finish_date desc"
#Use SQLCmd to execute the query on the server
Invoke-Sqlcmd -ServerInstance $SQLServer -Query $Query

powershell - variable inside a string variable shall update even after it was declared

As you can see, the variable $SQLRCNumberNew is inside another variable $SQLUpdateRC which has been declared before $SQLRCNumberNew did.
When I am running the script $SQLRCNumberNew is empty, which makes sense because it is declared inside $SQLUpdateRC at the beginning.
What I want to ask if someone has an idea how I can update $SQLRCNumberNew even it is declared at the beginning.
I know I can just put the string Variable right below, but this is not what I am looking for.
Thanks for any help!
$RCFirstDigit = 0
$RCSecondDigit = 0
$PhoenixDBServer = "Servername"
$PhoenixDBName = "Databasename"
$ProductionDBServer = "Servername"
$ProductionDBName = "Databasename"
$SQLSelectRC = $("SELECT [Char_Value_01] FROM [dbo].[TABLENAME] WHERE [Keyword] = 'Version Number'")
$SQLUpdateRC = $("UPDATE TABLENAME set Char_Value_01 = '$SQLRCNumberNew' where Keyword = 'Version Number'")
Switch ($env:COMPUTERNAME) {
$PhoenixDBServer {
$Server = $PhoenixDBServer + "." + $env:USERDNSDOMAIN
$Database = $PhoenixDBName
}
$ProductionDBServer {
$Server = $ProductionDBServer + "." + $env:USERDNSDOMAIN
$Database = $ProductionDBName
}
default {
Write-Verbose "This script does not run on this computer"
exit
}
}
$SQLRCNumber = Invoke-Sqlcmd -ServerInstance $Server -Database $Database -Query $SQLSelectRC
[int]$RCFirstDigit = $SQLRCNumber.Char_Value_01.split(".")[1]
[int]$RCSecondDigit = $SQLRCNumber.Char_Value_01.split(".")[2]
$RCSecondDigit++
# put string back together with updated RC number
[string]$SQLRCNumberNew = $SQLRCNumber.Char_Value_01.Split(".")[0] + "." + $RCFirstDigit + "." + $RCSecondDigit
# Update RC Version on Database
Invoke-Sqlcmd -ServerInstance $Server -Database $Database -Query $SQLUpdateRC
Just to be clear - this is not how PowerShell scripting works. When you assign data to your variables, at least when working with strings.
You could have a function inside your script file, that you could call and have it return the concatenated string.
Function StringBuilder {
Param ($Value)
"UPDATE TABLENAME set Char_Value_01 = '$Value' where Keyword = 'Version Number'"
}
...
$SQLRCNumber = Invoke-Sqlcmd -ServerInstance $Server -Database $Database -Query $SQLSelectRC
$SQLUpdateRC = StringBuild $SQLRCNumber
Invoke-Sqlcmd -ServerInstance $Server -Database $Database -Query $SQLUpdateRC
...
Something like that should work. But I would say you should have a string format defined in the top and simply format when you need it.
$SQLUpdateRCBase = "UPDATE TABLENAME set Char_Value_01 = '{0}' where Keyword = 'Version Number'"
...
$SQLRCNumber = Invoke-Sqlcmd -ServerInstance $Server -Database $Database -Query $SQLSelectRC
$SQLUpdateRC = $SQLUpdateRCBase -f $SQLRCNumber
Invoke-Sqlcmd -ServerInstance $Server -Database $Database -Query $SQLUpdateRC