How to select last X records in SQL using Read-SqlTableData in Powershell - sql

So I'm writing a powershell script and utilizing the Module "sqlserver" to use the "Read-SqlTableData" cmdlet. I see there is a -topN X filter which selects from the top of the datatable but the way our table is set up, the oldest records at at the top but im trying to get newer records. Is there a way to select the last X records from the bottom?
This is what i have now. Any help is appreciated!
$SQLData=Read-SqlTableData -ServerInstance "Server" -Database "Database" -SchemaName "schema" -tablename "table" -ColumnName "column","column2","column3"

I do it like this, run a query and get the exact data you need.
try
{
$ConnectionString = "Server=$($DatabaseServer);Integrated Security=true;Initial Catalog=$($DatabaseName)"
$Query = "SELECT TOP $($BatchSize) * FROM [$($DatabaseName)].[dbo].[$($TableName)] WHERE $($colStatus) = 30"
Write-Host "DEBUG: `$Query is $Query " -ForegroundColor DarkYellow
$sqlConn = New-Object System.Data.SqlClient.SqlConnection
$sqlConn.ConnectionString = $ConnectionString
$sqlConn.Open()
$sqlcmd = New-Object System.Data.SqlClient.SqlCommand
$sqlcmd.Connection = $sqlConn
$sqlcmd.CommandText = $Query
$adp = New-Object System.Data.SqlClient.SqlDataAdapter $sqlcmd
$tbldata = New-Object System.Data.DataSet
$adp.Fill($tbldata) | Out-Null
try {$sqlConn.Close()} catch {}
}
catch
{
$errorMsg = "ERROR: Cannot connect to Database $DatabaseName using the following Connection String $ConnectionString. Query is $Query. Get-KLMigrationSQLData."
}
if ($tbldata)
{
Write-Host "DEBUG: Creating `$VDB Global Variable from Database Table:
$TableName" -ForegroundColor DarkYellow
$dataFill = New-Variable -Name "VDB" -Force -PassThru -Scope Global
$dataFill.Value = #()
foreach ($DBRow in $tbldata.Tables.Rows)
{
$tempObj = New-Object System.Object
$tempObj | Add-Member -Type NoteProperty -Name TableName -Value $TableName
$DBRows = $DBRow | Get-Member | Where-Object {$_.MemberType -eq 'Property' -or $_.MemberType -eq 'ParameterizedProperty'}
ForEach ($Row in $DBRows){
if ($Row.Name -ne 'Item')
{
$colName = $Row.Name
$colValue = $DBRow.Item($colName)
$tempObj | Add-Member -Type NoteProperty -Name $colName -Value $colValue
}
}
$dataFill.Value += $tempObj
}
}

Related

Powershell connect to several INSTANCES of SQL Server

I need to create a script that do:
Get services where name are like MSSQL$* (in order to get all SQL Server instances services)
If the service are running, goes to check name
If the name of the service is like MSSQL$MICROSOFT##WID, throw a System.Exception
If not, try to connect to every instances running on the server, if one of them are inaccessible, throw a System.Exception
My current script:
$ErrorActionPreference = "Stop"
try {
$running = Get-Service | where {($_.Status -eq "Running") -and $_.Name -like "MSSQL*"}
$services = (Get-Service -Name 'MSSQL*')
$running.Status | Foreach-object {
if ($running.status -contains 'Running'){
if ($_.Name -ne 'MSSQL$MICROSOFT##WID'){
$instances = (get-itemproperty 'HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server').InstalledInstances
foreach ($instance in $instances){
$server = "localhost"
$database = "master"
$sql = "select name from sys.databases"
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "Server=$server;Database=$database;Integrated Security=SSPI"
$SqlConnection.Open()
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.CommandText = $sql
$SqlCmd.Connection = $SqlConnection
$SqlAdapter = New-Object System.Data.SqlClient.SqlDataAdapter
$SqlAdapter.SelectCommand = $SqlCmd
$DataSet = New-Object System.Data.DataSet
$SqlAdapter.Fill($DataSet)
$SqlConnection.Close()
$DataSet.Tables[0]
$return = ($DataSet.Tables[0])
if ($return -ne $null){return 1} else {[System.Exception]}
}}
} else {[System.Exception]}
}}catch{[System.Exception]}
finally{$ErrorActionPreference = "Stop"}
Check status of services with MSSQL*
If status of services is running, check name of service, if the name of service is equal to MSSQL$MICROSOFT##WID throw a System.Exception, if not, list all instances and then, foreach instance in instances, try to connect
If the connection is successful, return 1, if not, throw System.Exception
My questions are: with this script, doesn't matter how many instances have already installed in the server, only check the default... how can I make try the connection for every instance that is running?
I need to check the connection to each instance running on the server, if there is someone stopped, or inaccessible must throw a System.Exception.
And too, is not possible use dbatools, and invokesql...
Somebody knows how to make the connection to every instances running on the server, if one of them are inaccessible, throw a System.Exception?
------------------- UPDATED ------------------------
this string succesfully connect with an example of instance
$SqlConnection.ConnectionString = "Server='localhost\NEWINSTANCE';Database=master;Integrated Security=SSPI"
I just try to send the server trough variable, but give me error...
if ($_.Name -ne 'MSSQL$MICROSOFT##WID'){
$SQLinstancesold = dir "SQLSERVER:\SQL\(local)"
$SQLinstances = $SQLinstancesold | Format-table -HideTableHeaders
foreach ($SQLinstance in $SQLInstances) {
$server = 'localhost\'+$SQLinstance;
$database = "master"
$sql = "select name from sys.databases"
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "Server='localhost\NEWINSTANCE';Database=master;Integrated Security=SSPI"
$SqlConnection.Open()
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.CommandText = $sql
$SqlCmd.Connection = $SqlConnection
$SqlAdapter = New-Object System.Data.SqlClient.SqlDataAdapter
$SqlAdapter.SelectCommand = $SqlCmd
$DataSet = New-Object System.Data.DataSet
$SqlAdapter.Fill($DataSet)
$SqlConnection.Close()
$DataSet.Tables[0]
$return = ($DataSet.Tables[0])
if ($return -ne $null){return 1} else {echo "else of return 1"}
}}
I dont know how can I pass the variable to connectionstring in order to do the connection for each instance
--------------------------- UPDATED 2 -----------------------
I just modified the script:
Import-Module SQLPS -DisableNameChecking
$ErrorActionPreference = "Stop"
try {
$running = Get-Service | where {($_.Status -eq "Running") -and $_.Name -like "MSSQL*"}
$services = (Get-Service -Name 'MSSQL*')
$running.Status | Foreach-object {
if ($running.status -contains 'Running'){
if ($_.Name -ne 'MSSQL$MICROSOFT##WID'){
$SQLinstancesold = dir "SQLSERVER:\SQL\(local)"
$SQLinstances = $SQLinstancesold | Format-table -HideTableHeaders
$server = 'localhost\'+$SQLinstance;
foreach ($SQLinstance in $SQLInstances) {
$server = 'localhost\'+$SQLinstance;
$return = Invoke-Sqlcmd -ServerInstance $server -Database master -Query "select name from sys.databases"
if ($return -ne $null){return 1} else {echo "else of return 1"}
}}
} else {echo "here"}
}
}
catch{echo "hello?"}
finally{$ErrorActionPreference = "Stop"}
This way, list all instances, and for each instance declare variable server and try to invoke-sqlcmd
But, when I try to invoke $server on $return variable, give me an error, if I write for example the name of my instance NEWINSTANCE, return 1, that is correct
How can I put variable $server in order to get all instances on invokesqlcmd?

How to use powershell to obtain the data from excel and select from SQL

I have an excel file that contain a list of staff information,
now I want to use the column Staff_ID in xlsx to select those Staff_ID from sql table and get the result by export_CSV, so I try to write a powershell that could be run in schedule task.
How should I get the information from excel and select those data from sql table?
$SQLServer = "ServerName"
$SQLDBName = "DBName"
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "Server = $SQLServer; Database =
$SQLDBName; User ID= YourUserID; Password= YourPassword"
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.CommandText = 'StoredProcName'
$SqlCmd.Connection = $SqlConnection
$SqlAdapter = New-Object System.Data.SqlClient.SqlDataAdapter
$SqlAdapter.SelectCommand = $SqlCmd
$DataSet = New-Object System.Data.DataSet
$SqlAdapter.Fill($DataSet)
$SqlConnection.Close()
$gSqlAuthMode = True
SELECT * FROM [DBName].[dbo].[DETAILS] WHERE [STATUS] not like 'Inactive-%' ORDER BY NUMBER ASC
$List = Import-XLSX -Path "D:\Stafflist.xlsx"
foreach ($item in $List){
If ((?? -eq $item.StaffCuid.toUpper().trim())) {
$Report = [PSCustomObject] #{
}
}
}
$Report | Export-Csv D:\report.csv -Delimiter "," -NoTypeInformation -append
}
You could use Import-Excel cmdlet from the famous ImportExcel module and Invoke-SQLCmd (part of SQL management tools)
$Excel = Import-Excel -Path D:\Stafflist.xlsx
Foreach($Row in $Excel) {
$StaffID = $Row.StaffCuid.toUpper().trim()
$Query = "create your query here with $StaffId"
Invoke-SQLCmd -Query $Query -ServerInstance "$ServerName\$DBName"
}

Insert Microsoft Updates into Database

I'm trying to modify this script so that it inserts the installed updates into an SQL Server database table.
$conn = New-Object System.Data.SqlClient.SqlConnection
$conn.ConnectionString = "Data Source=sqlserver; Initial Catalog=updates; Integrated Security=SSPI;"
$conn.Open()
$cmd = New-Object System.Data.SqlClient.SqlCommand
$cmd.Connection = $conn
$cmd = $conn.CreateCommand()
$wu = new-object -com “Microsoft.Update.Searcher”
$totalupdates = $wu.GetTotalHistoryCount()
$all = $wu.QueryHistory(0,$totalupdates)
$OutputCollection= #()
Foreach ($update in $all){
$Regex = “KB\d*”
$KB = $string | Select-String -Pattern $regex | Select-Object { $_.Matches }
$output = New-Object -TypeName PSobject
$output | add-member NoteProperty “HotFix ID” -value $KB.‘ $_.Matches ‘.Value
$output | add-member NoteProperty “Title” -value $string
$OutputCollection += $output
$cmd.CommandText += "INSERT INTO dbo.updates (hotfixid, hotfixdescription) VALUES ('$($kb.'$_.Matches'.Value)', ('$($string)'))"
}
$cmd.ExecuteNonQuery()
$conn.close()
At the moment, I'm getting correct number of rows for updates in sql server but it isn't showing hotfixid and in hotfix descriptien columns there is a only one update in all rows.
Thanks!
Do the INSERTs inside the loop. I would, however, recommend that you use prepared statements instead of building the SQL statements via string concatenation. Also, there's no need to build $OutputCollection objects when you're not using it anywhere.
Something like this should work:
...
$wu.QueryHistory(0, $totalupdates) | % {
$KB = $_.Title | ? { $_ -match '(KB\d+)' } | % { $matches[1] }
$cmd = $conn.CreateCommand()
$cmd.CommandText = "INSERT INTO dbo.updates (hotfixid, hotfixdescription) " +
"VALUES (#id, #descr)"
$cmd.Parameters.AddWithValue("#id", $KB)
$cmd.Parameters.AddWithValue("#descr", $_.Title)
$cmd.Prepare()
$cmd.ExecuteNonQuery()
}
...
Untested, though, since I don't have an SQL Server at hand. I also suspect that there's a more efficient way to handle the prepared statements, but I'm not that familiar with SQL Server.

Powershell array correlation to SQL table dataset from powershell

First off, I'm new to stack. I have referenced stack many times in the past, but recently I have been stuck on this issue for quite sometime. So here goes.
My goal:
I am attempting to correlate an array output from VMware that matches a custom value on each VM machine. ( an asset ID ) to a value ( ID Key ) on a microsoft SQL 2000 server.
As such, since this server is pre 2005 I am unable to use the invoke-sqlcmd powershell command. I have to utilize the full SQL connection string and command structure to return a value out of this database. This sql statement and script works fine on its own. Meaning that the sql portion of this script, functioning on its own will pull results out of the database with a manual tag number put in place of my variable "$etag". I'm fairly new to powershell, and sql use from powershell.
So here is my script with names of the protected taken out.
#========================================================================
# Created on: 12/4/2013 2:01 PM
# Created by: Shaun Belcher
# Filename:
#========================================================================
function get-inventory
{
Add-PSSnapin VMware.VimAutomation.Core
$date=get-date
$vcenterserver = #("srv-1","srv-2","srv-3")
Connect-VIServer -server $vcenterserver
$toAddr="user#domain.com"
$fromAddr="user#domain.com"
$smtpsrv="mail.domain.com"
#Variables
$mdesks=#()
$sqlServer = "serverdb"
$sqlDBNAME = "instance"
$sqlAdapter = New-Object System.Data.SqlClient.SqlDataAdapter
$sqlConnection = New-Object System.Data.SqlClient.SqlConnection
$DataSet = New-Object System.Data.DataSet
$sqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.connection = $sqlConnection
$sqlAdapter.SelectCommand = $sqlCmd
#db Connection
$sqlConnection.ConnectionString = "Server = $sqlServer; Database = $sqlDBname; Integrated Security=True;"
$SqlCmd.connection = $SqlConnection
$SqlCmd.commandtext = $sqlQuery
$sqlAdapter.SelectCommand = $sqlCmd
$sqlQuery += "SELECT INVHARDW_PropTag as proptag, invhardw_clientID as ClientID, invhardw_notes as Notes FROM INV_Hardware where invhardw_proptag = '$etag';"
$SqlCmd.commandtext = $sqlQuery
$sqlAdapter.SelectCommand = $sqlCmd
$sqlAdapter.Fill($DataSet)
$DataSet.Tables[0]
$sqlConnection.Close()
$mdesks = #($DataSet.Tables[0] | select propTag, ClientID, Notes)
$virtuals= #(Get-VM | select Name,vmhost,memoryMB,#{N="Datastore";E={[string]::Join(',',(Get-Datastore -Id $_.DatastoreIdList | Select -ExpandProperty Name))}})
$etags = #(Get-vm | Get-Annotation |select value,#{N="mDeskNote";E={[string]::Join(',',($mdesk | Where-Object {$mdesks.propTag = $_;}))}},#{N="mDeskClientID";E={[string]::Join(',',($mdesk | Where-Object {$mdesks.propTag = $_;}))}})
if($virtuals -ne $null){
$body = #("
<center><table border=1 width=50 % cellspacing=0 cellpadding=8 bgcolor=Black cols=3>
<tr bgcolor=White><td>Virtual Machine</td><td>Host Machine</td><td>Memory Allocated</td><td>DatastoreList</td><td>Asset Tag</td><td>App Note</td><td>App Client ID</td></tr>")
$i = 0
do {
#if($i % 2){$body += "<tr bgcolor=#D2CFCF><td>$($virtuals[$i].Name)</td></tr>";$i++}
#else {$body += "<tr bgcolor=#EFEFEF><td>$($virtuals[$i].Name)</td></tr>";$i++}
if($i % 2){$body += "<tr bgcolor=#D2CFCF><td>$($virtuals[$i].Name)</td><td>$($virtuals[$i].VMHost)</td><td>$($virtuals[$i].MemorymB)</td><td>$($virtuals[$i].datastore)</td><td>$($etags[$i].value)</td><td>$mdesks[$i].notes</td><td>$mdesks[$i].ClientID</td></tr>";$i++}
else {$body += "<tr bgcolor=#EFEFEF><td>$($virtuals[$i].Name)</td><td>$($virtuals[$i].VMHost)</td><td>$($virtuals[$i].memorymb)</td><td>$($virtuals[$i].datastore)</td><td>$($etags[$i].value)</td><td>$mdesks[$i].notes</td><td>$mdesks[$i].ClientID</td></tr>";$i++}
}
while ($virtuals[$i] -ne $null)
$body += "</table></center>"
# Send email.
if($attachmentPref){
$virtuals | Export-CSV "Inventory $($date.month)-$($date.day)-$($date.year).csv"
Send-MailMessage -To "$toAddr" -From "$fromAddr" -Subject "$vcenterserver Inventory = $countvms" -Body "$body" -Attachments "Inventory $($date.month)-$($date.day)-$($date.year).csv" -SmtpServer "$smtpsrv" -BodyAsHtml
Remove-Item "Inventory $($date.month)-$($date.day)-$($date.year).csv"
}
Else{
Send-MailMessage -To "$toAddr" -From "$fromAddr" -Subject "Inventory $vcenterserver = $countvms" -Body "$body" -SmtpServer "$smtpsrv" -BodyAsHtml
}
}
Disconnect-VIServer -Server $vcenterserver -Confirm:$false exit
get-inventory
This returns the information and sends it in an email with columns and rows of the information. Again, these are two working scripts that just do not return the result that is sought after.

Multithreading Help w/Powershell

So I have a script that will go through and ping all the servers from a list that is stored in SQL Server. The script works fine but it does it all sequentially (lame).
Can someone help me out as to how I would change this to use multithreading instead of a foreach loop?
$Server = "ServerName"
$Database = "DatabaseName"
$con = "server=$Server;database=$Database;Integrated Security=sspi"
$cmd = "SELECT ServerName FROM dbo.vwServerListActive"
$da = new-object System.Data.SqlClient.SqlDataAdapter ($cmd, $con)
$dt = new-object System.Data.DataTable
$da.fill($dt) | out-null
foreach ($srv in $dt)
{
$ping = new-object System.Net.NetworkInformation.Ping
$Reply = $ping.send($srv.ServerName)
$ServerName = $srv.ServerName
$ServerName
$Reply.status
if ($Reply.status –eq “Success”)
{
$sql = "UPDATE dbo.ServerList SET GoodPing = 1 WHERE GoodPing <> 1 AND ServerName = '$ServerName'"
}
else
{
$sql = "UPDATE dbo.ServerList SET GoodPing = 0 WHERE GoodPing <> 0 AND ServerName = '$ServerName'"
}
$Reply = ""
invoke-sqlcmd -serverinstance $Server -database $Database -query $sql
}
(Edited as per Chad Miller's Suggestion + Throttling Requirement + Wait-Job fix + STA fix)
Support.ps1
powershell -File "Main.ps1" -Sta
Main.ps1
$Server = "ServerName"
$Database = "DatabaseName"
$con = "server=$Server;database=$Database;Integrated Security=sspi"
$cmd = "SELECT ServerName FROM dbo.vwServerListActive"
$da = New-Object System.Data.SqlClient.SqlDataAdapter -ArgumentList $cmd, $con
$dt = New-Object System.Data.DataTable
$da.Fill($dt) | Out-Null
$ThrottleLimit = 10
$activeJobs = New-Object 'System.Collections.Generic.List[Int32]'
$JobStateChanged = {
param (
[System.Object]$Sender,
[System.Management.Automation.JobStateEventArgs]$EventArgs
)
switch ($EventArgs.JobStateInfo.State)
{
Blocked { return }
Completed { $activeJobs.Remove($Sender.Id); break }
Failed { $activeJobs.Remove($Sender.Id); break }
NotStarted { return }
Running { return }
Stopped { $activeJobs.Remove($Sender.Id); break }
}
Unregister-Event -SourceIdentifier ("{0}.StateChanged" -f $Sender.Name)
}
foreach ($srv in $dt)
{
while ($true)
{
if ($activeJobs.Count -lt $ThrottleLimit)
{
$job = Start-Job -InitializationScript {
Add-PSSnapin -Name SqlServerCmdletSnapin100
} -ScriptBlock {
param (
[String]$Server,
[String]$Database,
[String]$ServerName
)
if (Test-Connection -ComputerName $ServerName -Quiet)
{
$sql = "UPDATE dbo.ServerList SET GoodPing = 1 WHERE GoodPing <> 1 AND ServerName = '$ServerName'"
}
else
{
$sql = "UPDATE dbo.ServerList SET GoodPing = 0 WHERE GoodPing <> 0 AND ServerName = '$ServerName'"
}
Invoke-SqlCmd -ServerInstance $Server -Database $Database -Query $sql
} -ArgumentList $Server, $Database, $srv.ServerName
$activeJobs.Add($job.Id)
Register-ObjectEvent -InputObject $job -EventName StateChanged -SourceIdentifier ("{0}.StateChanged" -f $job.Name) -Action $JobStateChanged
break
}
}
}
Get-Job | Where-Object { $_.State -eq "Running" } | Wait-Job
Get-Job | Remove-Job
If have PowerShell 2.0 you could make use of background jobs. You'll need to break up your server list into "groups". Given a source table with serverName and groupName:
CREATE TABLE [dbo].[vwServerListActive](
[serverName] [varchar](50) NULL,
[groupName] [char](1) NULL
)
A slight modification to your script (save as forum.ps1):
param($groupName)
$Server = "$env:computername\sql2k8"
$Database = "dbautility"
$con = "server=$Server;database=$Database;Integrated Security=sspi"
$cmd = "SELECT ServerName FROM dbo.vwServerListActive WHERE groupName ='$groupName'"
$da = new-object System.Data.SqlClient.SqlDataAdapter ($cmd, $con)
$dt = new-object System.Data.DataTable
$da.fill($dt) | out-null
foreach ($srv in $dt)
{
$ping = new-object System.Net.NetworkInformation.Ping
$Reply = $ping.send($srv.ServerName)
new-object PSObject -Property #{ServerName=$($srv.ServerName); Reply=$($Reply.status)}
}
You can then call the script for different groups:
#groupName A
start-job -FilePath .\forum.ps1 -Name "Test" -ArgumentList "A"
#groupName B
start-job -FilePath .\forum.ps1 -Name "Test" -ArgumentList "B"
Get-Job -name "test" | wait-job | out-null
Get-Job -name "test" | receive-job
#get-job -name "test" |remove-job
If you're using PowerShell V1 or sqlps you could use System.Diagnostics.ProcessStartInfo to start separate powershell.exe processes and pass the group name.
param($groupName)
$StartInfo = new-object System.Diagnostics.ProcessStartInfo
$StartInfo.FileName = "$pshome\powershell.exe"
$StartInfo.Arguments = " -NoProfile -Command C:\scripts\forum.ps1 $groupName"
$StartInfo.WorkingDirectory = "C:\scripts"
$StartInfo.LoadUserProfile = $true
$StartInfo.UseShellExecute = $true
[System.Diagnostics.Process]::Start($StartInfo) > $null
Here's a page with a script which might be useful for you. I haven't used it myself yet, so I can't comment on it beyond that.
Powershell doesn't really do multithreading at all. I've managed to crowbar it into place by faking it with a fire-and-forget script kicked off with "start [powershell path] scriptname.ps1". It'll fire off multiple insances, but you can't get data back from them without doing an end-run by way of a database or other message passing mechanism. Tracking when the child processes terminate is tricky as well.
cmd /c "start /min /low C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -command .\evtlogparse.ps1 "
In your case as you're setting a SQL string as part of the foreach loop, you can try to put the DB update code into a second script that you fire off. You'll potentially have many different processes attempting to update the same database table, so the potential for timing issues is pretty large.
Also, since you're kicking off umpty new powershell instances you're going to eat a lot of memory to make it work. The foreach loop may just be faster than kicking off a bunch of processes.
So, it can be done, but it isn't anything even resembling pretty.
First, I suggest to only create once the variable $ping outside of the 'foreach..'.
Maybe a simpler solution... now that you're using SQL 2008, why not using the SMO method 'enumAvailableSqlServers: "...SMOApplication]::EnumAvailableSqlServers($false)". This will give you a list of all available server on the network. Here's the Microsoft MSDN link so you can read about it:
http://msdn.microsoft.com/en-us/library/ms210350.aspx
so close.... this is what I've got
add-pssnapin SqlServerCmdletSnapin100
$Server = "ServerName"
$Database = "DatabaseName"
$con = "server=$Server;database=$Database;Integrated Security=sspi"
$cmd = "SELECT ServerName FROM dbo.vwServerListActive"
$da = New-Object System.Data.SqlClient.SqlDataAdapter -ArgumentList $cmd, $con
$dt = New-Object System.Data.DataTable
$da.Fill($dt) | Out-Null
foreach ($srv in $dt)
{
Start-Job -ScriptBlock {
param (
[String]$Server,
[String]$Database,
[String]$ServerName
)
if (Test-Connection -ComputerName $ServerName -quiet)
{
$sql = "UPDATE dbo.ServerList SET GoodPing = 1 WHERE GoodPing <> 1 AND ServerName = '$ServerName'"
}
else
{
$sql = "UPDATE dbo.ServerList SET GoodPing = 0 WHERE GoodPing <> 0 AND ServerName = '$ServerName'"
}
Invoke-SqlCmd -ServerInstance $Server -Database $Database -Query $sql
} -ArgumentList $Server, $Database, $srv.ServerName
}
and it looks to be starting multiple jobs... but my table never gets updated. If I remove the "Start-Job" stuff and arguement list and use $srv.ServerName then it works sequentially as it did before. Any ideas? (Thanks so much BTW for all the responses)
Here's a script from Jim Truher for background jobs in PowerShell v1.0:
http://jtruher.spaces.live.com/blog/cns!7143DA6E51A2628D!130.entry
PowerShell v2.0 has background jobs built-in:
http://technet.microsoft.com/en-us/library/dd347692.aspx
-Oisin