Powershell Invoke-Sqlcmd string output - sql

I am querying data from SQL server.
$usersStatus = Invoke-Sqlcmd `
-query "USE Database
SELECT [Status],[ID]
FROM [tblUsers]" `
-ServerInstance "Sqlserver\sqlinst" | Select-Object ID,Status
Getting output from query:
foreach ($user in $usersStatus)
{
Write-Host "asd"$user.Status"asdad"
}
Output:
asd Queued asdad
asd Queued asdad
asd Queued asdad
asd Queued asdad
Question:
I would like to kindly ask, if any one know why I always have white space in string please?
Do I realy have to use trim() like: Write-Host "asd"$user.Status.trim()"asdad" with every string I am reciving from Invoke-Sqlcmd. What if my project has 2000 lines? Is there nay trick to get string from SQL without White spaces please?

Related

How to query SQL Server using PowerShell

I have this code that I got from a website and it's connected to my SQL Server using window authentication but I'm not sure how can I choose a database and query some table?.
[Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo") | out-Null
$s = new-object ('Microsoft.SqlServer.Management.Smo.Server') "server instance"
$s.ConnectionContext.LoginSecure=$true
$s.Databases | select name, size, status
If I run this code, it show me a list of databases but I want to choose a database called "LitHold" and query some table from that database inside.
For SMO like you have in your question, you can run queries that return data using ExecuteWithResults() like so:
$s = New-Object Microsoft.SqlServer.Management.Smo.Server "server instance"
$db = $s.Databases.Item("master")
$query = "SELECT * FROM [master].[sys].[databases] ORDER BY [name];"
$result = $db.ExecuteWithResults($query)
# Show output
$result.Tables[0]

Powershell CSV output - cant delete rows and special charaters

I'm having trouble with a csv file. My script is collecting data from a SQL Table, then it should write result as a csv file. My problem is that the csv file my code currently creates has speech marks and two rows of header that i don't want.
Right now my file looks like this:
TYPE System.Data.DataRow
code,"order","price"
product1,"1","207,75"
product2,"1","95,24"
I would like it to look like this:
product1;1;207,7
product2;1;95,24
My code:
$VAR1 = "select [product], [order], [price] from TABLE1
$VAR2 = Invoke-Sqlcmd -Query $VAR1 -serverinstance SERVER1
$Result | Export-Csv -path C:\test55.csv
You can remove the TYPE header line by using the -NoTypeInformation switch on Export-CSV.
I don't think you can switch off the speech marks, but they are useful in case one of your data values includes a comma in it. If you open the CSV in Excel the speech marks won't be visible, so they are honoured by things that read CSV. If you wanted to remove them you could do a -replace to do so but it would risk removing them where they are part of the data.
If you want to remove the header line, you could use ConvertTo-CSV and then use Select-Object to skip the first line of the output.
So for example:
$VAR1 = "select [product], [order], [price] from TABLE1"
$VAR2 = Invoke-Sqlcmd -Query $VAR1 -serverinstance SERVER1
($Result | ConvertTo-Csv -NoTypeInformation |
Select-Object -Skip 1) -Replace '"' |
Out-File C:\test55.csv

invoke-expression for SQLCMD -i "test.sql" and put results to a variable

I have a huge sql query where I want to run on a remote server from another server via powershell, however I am having trouble trying get the results per column per row of since test.sql produces a table with multiple table and result. I know I can query it using the
$ConnectionToServer = New-Object System.Data.SQLClient.SQLConnection
$CommandCMSQry = New-Object System.Data.SQLClient.SQLCommand
Where $CommandCMSQry contains the whole query in a string format. However, I am trying lessen the rows of the script thus I wanted to put the SQL query outside of the PS script.
$QryPath = "D:\CNA\DatabaseIntegrityCheck.sql"
invoke-expression "SQLCMD -E -S $InstanceNm -d 'master' -i $QryPath -b" | Tee-Object -Variable ResultCreateSP | Select-Object name,database_id
$ResultCreateSP
Example result:
main result
a b
1 foo1
2 foo2
and if I access the columns something with like this
write-host "a = " + $ResultCreateSP.name + "b = " + $ResultCreateSP.database_id
a = 1 b = foo1

Powershell SQL insert randomly fails

$timelimit = (get-date).AddMinutes(-65)
$logpath = "C:\_SCRIPT_\_SCHED_\_Eventlog_to_SQL.txt"
$now = get-date
$nowstring = "{0:yyyy-MM-dd-HH:mm:ss}" -f $now
$dbServer = "myserver"
$dbDatabase = "logdb"
$dbuid = "logdbuser"
$dbpwd = "logdbpass"
$dbTableFWevents = "dbo.fwevents"
$FWEvents = Get-WinEvent -logname ForwardedEvents | where-object {$_.timecreated -ge $timelimit} | Select * | Sort-Object TimeCreated
$FWEventsstat = $FWEvents | Measure-Object
$dbConnection = New-Object System.Data.SqlClient.SqlConnection
$dbConnectionString = "Server=$dbServer;Database=$dbDatabase;Integrated Security=True;User ID=$dbuid;Password=$dbpwd;Connect Timeout=0"
$dbconnection.ConnectionString = $dbConnectionString
$dbconnection.Open()
$transaction = $dbConnection.BeginTransaction("LogParserUpload")
$nowstring + " ---START---" | out-file $logpath -Append
$nowstring + " EVENT COUNT: " +$FWEventsstat.Count | out-file $logpath -Append
foreach ($evnt in $FWEvents)
{
$Command = $dbconnection.CreateCommand()
$Command.CommandText = "INSERT INTO "+$dbDatabase+"."+$dbTableFWevents+" (Message, Id, Level, ProviderName, LogName, ProcessId, ThreadId, MachineName, UserId, TimeCreated, LevelDisplayName) VALUES (#Message, #Id, #Level, #ProviderName, #LogName, #ProcessId, #ThreadId, #MachineName, #UserId, #TimeCreated, #LevelDisplayName)";
if ([string]$evnt.message){$Command.Parameters.Add("#Message", [string]$evnt.Message);}else{$Command.Parameters.Add("#Message", [DBNull]::Value);}
if ([string]$evnt.id){$Command.Parameters.Add("#Id", [string]$evnt.id);}else{$Command.Parameters.Add("#Id", [DBNull]::Value);}
if ([string]$evnt.level){$Command.Parameters.Add("#Level", [string]$evnt.level);}else{$Command.Parameters.Add("#Level", [DBNull]::Value);}
if ([string]$evnt.providername){$Command.Parameters.Add("#ProviderName", [string]$evnt.ProviderName);}else{$Command.Parameters.Add("#ProviderName", [DBNull]::Value);}
if ([string]$evnt.logname){$Command.Parameters.Add("#LogName", [string]$evnt.LogName);}else{$Command.Parameters.Add("#LogName", [DBNull]::Value);}
if ([string]$evnt.processid){$Command.Parameters.Add("#ProcessId", [string]$evnt.ProcessId);}else{$Command.Parameters.Add("#ProcessId", [DBNull]::Value);}
if ([string]$evnt.threadid){$Command.Parameters.Add("#ThreadId", [string]$evnt.threadId);}else{$Command.Parameters.Add("#ThreadId", [DBNull]::Value);}
if ([string]$evnt.machinename){$Command.Parameters.Add("#MachineName", [string]$evnt.MachineName);}else{$Command.Parameters.Add("#MachineName", [DBNull]::Value);}
if ([string]$evnt.userid){$Command.Parameters.Add("#UserId", [string]$evnt.UserId);}else{$Command.Parameters.Add("#UserId", [DBNull]::Value);}
if ([string]$evnt.timecreated){$Command.Parameters.Add("#TimeCreated", [string]$evnt.TimeCreated);}else{$Command.Parameters.Add("#TimeCreated", [DBNull]::Value);}
if ([string]$evnt.leveldisplayname){$Command.Parameters.Add("#LevelDisplayName", [string]$evnt.LevelDisplayName);}else{$Command.Parameters.Add("#LevelDisplayName", [DBNull]::Value);}
$Command.Transaction = $transaction
$eredmenyin = $Command.ExecuteNonQuery()
$nowstring + " INSERT RESULT: " +$eredmenyin | out-file $logpath -Append
}
$eredmenytr = $transaction.Commit()
$nowstring + " TRANSACTION RESULT: " +$eredmenyin | out-file $logpath -Append
$nowstring + " ---END---" | out-file $logpath -Append
#$transaction.Rollback()
$dbconnection.Close()
Hello guys.
For historical reasons we collect a bunch of server info through Windows server Forwarded Event solution.
Forwarded Events is not easy to collect from a collector computer as logparser and other solutions hardly access it.
So I decided to collect and uplaod it with Powershell.
The script runs every 60 minutes as scheduled job, collects events backward for 65 minutes.
The script runs fine. But from time to time it does skips 1-2 lines. I do not understand why. It does not skips a whole session - but for example if in a 65 minute interval there are 5 events, it uploads 4. Next time it runns fluently. Next time it again skips from 10 event 2 randomly.
I would like to know why. But I do not understand the reason AND I have no clue how could I log the actual insert command to fix it, or create other error handling.
(As you can see I implemented transaction as well - hopefully not wrongly, and transaction gives an ok as well).
Have no Idea how to find the reason and/or source of error.
The first Column is uniqid - Allow Nulls is "no" - because its the row identifier.
Other rows are - Allow Nulls "yes".
(btw as I told the skript works - as 70-80% of the evenlogs are uploaded, but only 20-30% is missing - absolutley randomly ...)
So i doubt this is the source of the issue.
I suspect there is two way of finding the problem.
1) log the actual SQL command from $command variable - but I did not found out how can be that done.
write-host $command.parameters
only writes the content of $Command.CommandText - means no info only the #### variables in it. So I do not know, how to doublecheck if the actual INSERT is not "wrong"
2) use somehow the transaction log (or other resource) to find out if the actual INSERT command "arrives" and if did "arrived" if it was denied and for what reason. As I am not really an SQL expert this kind of magic is way beyond my knowledge (and google did not helped me out neither :( )

Powershell Get-QADUser results to SQL table

I'm querying Active Directory with a string which loops through each domain controller in our system and returns a set of results. The script works great with export-csv but because we wish to retain all data in the custom info field (it contains carriage-returns) I'd like to export this directly into an SQL table.
The error reported by Powershell reads:
Exception calling "ExecuteNonQuery" with "0" argument(s): "Insert Error: Column name or >number of supplied values does not match table definition."
Which is a pretty verbose response, I've created and named the columns of each table to exactly match the output of the get-object.
Here's the output from the pipe:
SamAccountName : testuser
DisplayName : Test User (COMPANY)
info : Test Entry 1234567890
Test for output.
Entering
Multiple lines.
whenCreated : 09/11/2004 09:08:42
whenChanged : 19/07/2012 09:25:21
AccountExpires :
pwdLastSet : 13/06/2012 07:43:43
LastLogonTimestamp : 18/07/2012 15:38:35
userAccountControl : 512
Name : Test User
LastLogon :
DC : DCNAME1
And here's the code:
##--AD data output to SQL script, you need the Quest plugin!
$SamAccountName = Read-Host "Enter the username to query for last logon"
##--Query domain for all domain controllers and funnel into a forEach loop
Get-QADComputer -ComputerRole DomainController | Foreach-Object{
$dc = $_.Name
##--Query each domain controller for the user object and retrieve the LastLogon timestamp
$user = Get-QADUser -Service $dc -SamAccountName $SamAccountName -IncludedProperties info,pwdLastSet,AccountExpires,userAccountControl | Select-Object SamAccountName,displayName,info,whenCreated,whenChanged,accountExpires,pwdLastSet,lastLogonTimestamp,userAccountControl,name,LastLogon,#{n='DC';e={$dc}} |
out-host
##--Open database connection
$conn = New-Object System.Data.SqlClient.SqlConnection("Data Source=SQLSERVER; Initial Catalog=ADomain; Integrated Security=SSPI")
$conn.Open()
##--AAGH! How to grab the results of the Select-Object above?
$cmd = $conn.CreateCommand()
$cmd.CommandText ="INSERT extract VALUES ('$user')"
$cmd.ExecuteNonQuery()
##--Don't forget to close it!
$conn.Close()
Now I'm messing something up which is probably plainly obvious, any help much appreciated.
Assume the following test object:
$exampleObject = New-Object PSObject -Property #{SamAccountName="TestSAN";DisplayName="TestDN"}
$user = $exampleObject | Select-Object SamAccountName, DisplayName
##--AAGH! How to grab the results of the Select-Object above?
$commandText = "INSERT extract VALUES ('$($user.SamAccountName)','$($user.DisplayName)'"
I would also move the sql connect and close to outside of a loop and place it in a try/finally block, so it is only done once instead of for each DC entry and the Close is still called when there is an Exception during the execution of the try block. See here for reference on using a try/catch/finally block with Powershell.
here I'm using SqlServerCmdletSnapin and it's Invoke-sqlcmd. This script is using MSSQL database EMPLOYEE and table EMPLOYEE_DOMAIN. Hope it helps. Works fine for me..
Add-PSSnapin Quest.ActiveRoles.ADManagement
Add-PSSnapin SqlServerCmdletSnapin100
Add-PSSnapin SqlServerProviderSnapin100
$db_server = "10.3.18.55"
$db = "EMPLOYEE"
$table = "EMPLOYEE_DOMAIN"
$username = "import"
$pwd = "Okinawa84561"
# First, clear existing table
$sql_query_del = "DELETE FROM $table"
Invoke-Sqlcmd -ServerInstance $db_server -Database $db -Username $username -Password $pwd -Query $sql_query_del
# Get users with employeeID only and write their accountname and employeeID to DB
Get-QADUser -IncludeAllProperties | ? {$_.employeeID} | select sAMAccountName, employeeID | foreach {
$an = $_.sAMAccountName
$eid = $_.employeeID
Write-Host " sAMAccountName : $an employeeID : $eid"
$sql_query = "INSERT INTO $table (employeeID, domainName) VALUES ('$eid', '$an')"
Invoke-Sqlcmd -ServerInstance $db_server -Database $db -Username $username -Password $pwd -Query $sql_query
}