Powershell - Connection Occasionally Drops when Writing to SQL - sql

I have a PS Script that checks the DNS for our domain server.
The Powershell script runs every 15 minutes and usually is successful. However, occasional it fails at random with the error below but there is nothing consistent about it when it fails.
Exception calling "Open" with "0" argument(s): "A connection was successfully established with the server, but then an
error occurred during the login process. (provider: SSL Provider, error: 0 - An existing connection was forcibly closed
by the remote host.)"
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : SqlException
If I can't find the cause, I was wondering if there is a way to check for this error and automatically re-run the script?
Thanks in advance.
UPDATE: Code Below
Try
{
# Query DNS server, loop through each domain
Invoke-Command -ComputerName $dc -ScriptBlock `
{
Param($domains, $dnsserver)
$ConnectionString = 'Data Source=MYDB; Initial Catalog=MYCAT; Integrated Security=SECURE'
$Conn = New-Object System.Data.SqlClient.SqlConnection($ConnectionString)
$Conn.Open()
Foreach ($domain in $domains)
{
# Query specific record types
$results = (Resolve-DnsName $domain -Server $dnsserver -Type NS)
$results | Foreach-Object `
{
$name = $_.name
$type = $_.type
$value = $_.NameHost
$Sql = "INSERT INTO B5_DNSCheck([DOMAIN], [TYPE], [VALUE]) VALUES('$domain','$type','$value')"
$Cmd = $Conn.CreateCommand()
$Cmd.CommandText = $Sql
$Cmd.ExecuteNonQuery() | Out-Null
}
$results = (Resolve-DnsName $domain -Server $dnsserver -Type MX)
$results | Foreach-Object `
{
$name = $_.name
$type = $_.type
$value = $_.NameExchange
$Sql = "INSERT INTO B5_DNSCheck([DOMAIN], [TYPE], [VALUE]) VALUES('$domain','$type','$value')"
$Cmd = $Conn.CreateCommand()
$Cmd.CommandText = $Sql
$Cmd.ExecuteNonQuery() | Out-Null
}
}
} -ArgumentList $domains, $dnsserver
Write-Output "Completed DNS check"
}
catch
{
Write-Output "Error with Connection"
Stop-Transcript
Exit 2
}
}
Else
{
Write-Output "Error: Unable to conect to $dnsserver to check DNS at this time"
Stop-Transcript
Exit 2
}
# All done
Stop-Transcript

The answer was #TheMadTechnicians advice.
Adding in $ErrorActionPreference='Stop' and a try/catch worked perfect.

Related

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

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
}
}

What is returned from a SQL query into a PowerShell variable?

Here is the function I have setup that works just fine to send queries to a SQL database from PowerShell and return the results (the results are what I don't quite understand)
function Invoke-SQL
{
param (
[string]$server,
[string]$database,
[string]$Query
)
$connectionString = "Data Source=$server; " +
"Integrated Security=SSPI; " +
"Initial Catalog=$database"
$connection = new-object
system.data.SqlClient.SQLConnection($connectionString)
$command = new-object system.data.sqlclient.sqlcommand($Query, $connection)
$connection.Open()
$adapter = New-Object System.Data.sqlclient.sqlDataAdapter $command
$dataset = New-Object System.Data.DataSet
$adapter.Fill($dataSet) | Out-Null
$connection.Close()
$dataSet.Tables
}
If I run a query such as the one below (it returns no results, meaning there were no records that existed that matched the condition) why does it return nothing when I just put in $results? Why is the result 'Table' when I do Write-Host $results ? See below
PS>$results = Invoke-SQL -server 'servername' -database 'DBname' -Query "SELECT * FROM [DBname].[dbo].[TableName] WHERE UserID = 'x' AND ComputerName = 'x'"
PS>$results
PS>Write-Host $results
Table
When no records are found I thought it would be equal to "" or $null but it is not upon testing
$null test
PS>If ($results -eq $null) {
>> write-host "Null"}else{
>> write-host "Not Null"
>> }
Not Null
"" test
PS>If ($results -eq "") {
>> write-host "Empty"}else{
>> write-host "Not Empty"
>> }
If someone could explain this to me, and what options I might have in order to check if a query returns no results, that would be great!
Read the comments on the question post for more details.
In order to see if records were returned or not, this will return the number of rows (records) returned. Credit to #Bill_Stewart.
($results | Measure-Object).Count
#Tomalak provided a helpful link.
#BaconBits had this helpful tip to get the type of an object
$results.GetType().FullName
# or
$results | Get-Member
Thank you all for your help.

Database relocation, Detach/attach database, MS-SQL-Server-Management-Studio(2012)

In the next week we want to relocate our database from one server to another one.
On http://msdn.microsoft.com/en-us/library/ms187858%28v=sql.110%29.aspx
I read about detaching the database from the old location and attach it to the new location.
The problem is, that I don't have access to the file system of the server, I don't even know where exactly the server is physically located^^
Is there a way to relocate a database from one Server to another without the need to access the file system of the old Server?
You could use the Import/Export tool in SQL Server to copy the data directly which will create a new database in the destination location. The good thing about this is the new DB will work as you might expect since it is created from scratch on the target server, but that also means that you might have old, deprecated syntax in your stored procs or functions or whatever which won't work unless you lower the compatibility level (although that shouldn't be hard). also be aware of any possible collation conflicts (your old server might have SQL_Latin1_General_CP1_CI_AS and the new one might be Latin1_General_CI_AS which can cause equality operations to fail amongst other things).
In addition, if you have a big database then it'll take a long time, but I can't think of any other method off the of of my head which doesn't require some level of access to the file system as you'd still need to get to the file system to take a copy of a backup, or if using a UNC path for the backup the source server would need to be able to write to that location and you'd need to be able to access it afterwards. If anyone else can think of one I'd be interested because it would be a useful bit of knowledge to have tucked away.
Edit:
Should also have mentioned the use of Powershell and SMO - it's not really any different to using the Import/Export wizard but it does allow you to fine tune things. The following is a PS script I have been using to create a copy of a DB (schema only) on a different server to the original but with certain facets missing (NCIs, FKs Indeitites etc) as the copy was destined to be read-only. You could easily extend it to copy the data as well.
param (
[string]$sourceServerName = $(throw "Source server name is required."),
[string]$destServerName = $(throw "Destination server is required."),
[string]$sourceDBName = $(throw "Source database name is required."),
[string]$destDBName = $(throw "Destination database name is required"),
[string]$schema = "dbo"
)
# Add an error trap so that at the end of the script we can see if we recorded any non-fatal errors and if so then throw
# an error and return 1 so that the SQL job recognises there's been an error.
trap
{
write-output $_
exit 1
}
# Append year to destination DB name if it isn't already on the end.
$year = (Get-Date).AddYears(-6).Year
if (-Not $destDBName.EndsWith($year)) {
$destDBName+=$year
}
# Load assemblies.
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.ConnectionInfo") | out-null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SMO") | out-null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SmoExtended") | out-null
# Set up source connection.
$sourceSrvConn = new-object Microsoft.SqlServer.Management.Common.ServerConnection
$sourceSrvConn.ServerInstance = $sourceServerName
$sourceSrvConn.LoginSecure = $false
$sourceSrvConn.Login = "MyLogin"
$sourceSrvConn.Password = "xxx"
# Set up destination connection.
$destSrvConn = new-object Microsoft.SqlServer.Management.Common.ServerConnection
$destSrvConn.ServerInstance = $destServerName
$destSrvConn.LoginSecure = $false
$destSrvConn.Login = "MyLogin"
$destSrvConn.Password = "xxx"
$sourceSrv = New-Object Microsoft.SqlServer.Management.SMO.Server($sourceSrvConn)
$sourceDb = New-Object ("Microsoft.SqlServer.Management.SMO.Database")
$destSrv = New-Object Microsoft.SqlServer.Management.SMO.Server($destSrvConn)
$destDb = New-Object ("Microsoft.SqlServer.Management.SMO.Database")
$tbl = New-Object ("Microsoft.SqlServer.Management.SMO.Table")
$scripter = New-Object Microsoft.SqlServer.Management.SMO.Scripter($sourceSrvConn)
# Get the database objects
$sourceDb = $sourceSrv.Databases[$sourceDbName]
$destDb = $destSrv.Databases[$destDbName]
# Test to see databases exist. Not as easy to test for servers - if you got those wrong then this will fail and throw an error
# so it's down to the user to check their values carefully.
if ($sourceDb -eq $null) {throw "Database '" + $sourceDbName + "' does not exist on server '" + $sourceServerName + "'"}
if ($destDb -eq $null) {throw "Database '" + $destDbName + "' does not exist on server '" + $destServerName + "'"}
# Get source objects.
$tbl = $sourceDb.tables | Where-object { $_.schema -eq $schema -and -not $_.IsSystemObject }
$storedProcs = $sourceDb.StoredProcedures | Where-object { $_.schema -eq $schema -and -not $_.IsSystemObject }
$views = $sourceDb.Views | Where-object { $_.schema -eq $schema -and -not $_.IsSystemObject }
$udfs = $sourceDb.UserDefinedFunctions | Where-object { $_.schema -eq $schema -and -not $_.IsSystemObject }
$catalogs = $sourceDb.FullTextCatalogs
$udtts = $sourceDb.UserDefinedTableTypes | Where-object { $_.schema -eq $schema -and -not $_.IsSystemObject }
$assemblies = $sourceDb.Assemblies | Where-object { -not $_.IsSystemObject }
# Set scripter options to ensure only schema is scripted
$scripter.Options.ScriptSchema = $true;
$scripter.Options.ScriptData = $false;
#Exclude GOs after every line
$scripter.Options.NoCommandTerminator = $false;
$scripter.Options.ToFileOnly = $false
$scripter.Options.AllowSystemObjects = $false
$scripter.Options.Permissions = $true
$scripter.Options.DriForeignKeys = $false
$scripter.Options.SchemaQualify = $true
$scripter.Options.AnsiFile = $true
$scripter.Options.Indexes = $false
$scripter.Options.DriIndexes = $false
$scripter.Options.DriClustered = $true
$scripter.Options.DriNonClustered = $false
$scripter.Options.NonClusteredIndexes = $false
$scripter.Options.ClusteredIndexes = $true
$scripter.Options.FullTextIndexes = $true
$scripter.Options.NoIdentities = $true
$scripter.Options.DriPrimaryKey = $true
$scripter.Options.EnforceScriptingOptions = $true
$pattern = "(\b" + $sourceDBName + "\b)"
$errors = 0
function CopyObjectsToDestination($objects) {
foreach ($o in $objects) {
if ($o -ne $null) {
try {
$script = $scripter.Script($o)
$script = $script -replace $pattern, $destDBName
$destDb.ExecuteNonQuery($script)
} catch {
#Make sure any errors are logged by the SQL job.
$ex = $_.Exception
$message = $o.Name + " " + (Get-Date)
$message += "`r`n"
#$message += $ex.message
$ex = $ex.InnerException
while ($ex.InnerException) {
$message += "`n$ex.InnerException.message"
$ex = $ex.InnerException
}
#Write-Error $o.Name
Write-Error $message # Write to caller. SQL Agent will display this (or at least some of it) in the job step history.
# Need to use Set-Variable or changes to the variable will only be in scope within the function and we want to persist this.
if ($errors -eq 0) {
Set-Variable -Name errors -Scope 1 -Value 1
}
}
}
}
}
# Output the scripts
CopyObjectsToDestination $assemblies
CopyObjectsToDestination $tbl
CopyObjectsToDestination $udfs
CopyObjectsToDestination $views
CopyObjectsToDestination $storedProcs
CopyObjectsToDestination $catalogs
CopyObjectsToDestination $udtts
# Disconnect from databases cleanly.
$sourceSrv.ConnectionContext.Disconnect()
$destSrv.ConnectionContext.Disconnect()
# Did we encounter any non-fatal errors along the way (SQL errors and suchlike)? If yes then throw an exception which tells the
# user to check the log files.
if ($errors -eq 1) {
throw "Errors encountered - see log file for details"
}

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.

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