Powershell Job within SQL Server Agent - sql

I am having trouble with a powershell job returning a result set when it runs, it runs successfully but no results. I am running it against a list of servers. If I run the script against a specific server that I know I can connect to, it runs fine and gives results.
This is a script within the sql server agent running powershell. Am I using the SMO object right? Ive tried to use a try/catch (job fails), ive tried to add -ErrorAction "Continue" to the script (job fails), using smo to resolve a server name in order to use the if statement (job succeeds) but no results. Here is the script:
$ErrorActionPreference = "Continue";
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SMO") | Out-Null
$instanceNameList = Get-Content "c:\Scripts\InPutFiles\servers.txt";
$results = #()
foreach($instanceName in $instanceNameList)
{
$serverObject = New-Object Microsoft.SqlServer.Management.Smo.Server($instanceName)
$serverName = $serverObject.ComputerNamePhysicalNetBIOS;
if($serverName -ne $null) {
$results += Invoke-Sqlcmd -Query "
(My Query is in here!)
" -ServerInstance $instanceName.Name}
$instanceName| Where-Object {$_} | Export-csv 'C:\scripts\HungJobs_UnabletoConnect.csv' -NoTypeInformation
}
$results| Where-Object {$_} | Export-csv 'C:\scripts\HungJobs.csv' -NoTypeInformation

Mid-way through your script, is the $scripts variable being populated properly by the Invoke-Sqlcmd?
If so, I'm thinking that you should be able to do away with Where-Object {$_} on your last two commands. Where-Object is used as a filter, and in these two cases it doesn't seem to be filtering anything. You should just be able to directly export the $instanceName and $results directly to csv.

Related

How to return multiple recordsets from stored procedure using PowerShell

I need to run a stored procedure that return 2 result sets with PowerShell. I use dbatools to do so but I could use .NET to get there. I just don't know how.
For this example, I use exec sp_spaceused that will return the space used in the actual database. Here's the result in SSMS:
As you can see here, there are 2 result sets. Now when I run the same command in PowerShell, I can't figure how to get the next result set.
Here is the code I've come up with:
$conn = Connect-DbaInstance -SqlInstance . -MultipleActiveResultSets
$query = 'exec sp_spaceused'
Invoke-DbaQuery -SqlInstance $conn -Query $query
I'm not even sure if I used MultipleActiveResultSets in the right way. I can't find any good example anywhere.
Wow, I just found the answer by testing all the different -As options. Here's the code:
$conn = Connect-DbaInstance -SqlInstance . -Database 'StackOverFlow'
$query = 'exec sp_spaceused'
$ds = Invoke-DbaQuery -SqlInstance $conn -Query $query -As DataSet
foreach ($table in $ds.Tables) {
$table | Out-String
}
I use Out-String to avoid joining objet but you could use Out-GridView. I also realize that I don't need to use -MultipleActiveResultSets.

VM power state not updated and returned correctly

I'm trying to power on VMs which I previously powered off using PowerCLI.
When I try to run the following script (part of a bigger one) I still get a status which is not "PoweredOn", even though I can see on the VSphere console that the machine was powered on.
I get this also in other situations and I try to re-get the virtual machines, but I fail to make this work.
If I don't re-get the VMs, I sometimes get error claiming the VM I'm referring to is null.
What am I doing wrong? What am I missing?
Here are the script lines:
$VMs = get-vm | Where-object {($_.Name -like $vmNamePatternToSearch)}# | Out-Null
foreach ($vm in $VMs) {
#$vm = Get-VM -Name $vm.Name #| Out-Null
if ($vm.powerstate -ieq "poweredoff") {
Start-VM -VM $vm -Confirm:$False | Out-Null
Write-Host -NoNewline 'Powering On' $vm.Name.ToString().PadRight(22)
do {
Start-Sleep -Seconds 1
Write-Host -NoNewline '|' $vm.powerstate
} until ($vm.powerstate -ieq "PoweredOn")
Write-Host
}
}
So my output is "| PoweredOff| PoweredOff| PoweredOff| PoweredOff| PoweredOff|..."
Even though the machine is already up.
Even if I un-comment the "#$vm = Get-VM -Name $vm.Name #| Out-Null" line - still no go.
I would appreciate your input.
Thanks!
PowerShell's objects are point in time references. So your vm variable will continue to reflect the status of the VM at the time you ran the get-vm cmdlet.
To help overcome this you could run something like the following to reference the updated state of the VM during your loop:
do {
Start-Sleep -Seconds 1
Write-Host -NoNewline '|' $vm.powerstate
} until ((Get-VM $vm).powerstate -ieq "PoweredOn")

Using PS to query SQL for list of users, then disable Active Directory accounts?

I'm trying to use Powershell to query SQL database for a list of suspended users, pipe into a variable, then use that to loop through and disable those AD accounts. Here's the code I'm using... note I'm just trying to write the output now instead of making a change so I don't do anything I regret.
Import-Module ActiveDirectory
$Users = Invoke-Sqlcmd -ServerInstance 'SERVER' -Database 'NAME' -Query "SELECT EmployeeID,
EmployeeStatus FROM [NAME].[dbo].[employee] WHERE EmployeeStatus = 'S'"
foreach ($user in $users)
{
Get-ADUser -Filter "EmployeeID -eq '$($user.EmployeeID)'" `
-SearchBase "OU=Logins,DC=domain,DC=com" |
#Set-ADUser -Identity $Name -Enabled $False
Write-Verbose $User
}
The SQL query is working fine, but when I run the loop it's giving this error:
Write-Verbose : The input object cannot be bound to any parameters for
the command either because the
command does not take pipeline input or the input and its properties do not match any of the parameters that take pipeline
input.
Am I just formatting this incorrectly? Or is there another way I should be thinking of this?
Thanks in advance!
If you would like to find inactive user accounts in Active Directory, you can use the Search-ADAccount cmdlet. You need to do this use the “-AccountInActive” parameter with Search-ADAccount.
PowerShell command below:
Search-ADAccount –AccountInActive –TimeSpan 120:00:00:00 –ResultPageSize 2000 –ResultSetSize $null | ?{$_.Enabled –eq $True} | Select-Object Name, SamAccountName, DistinguishedName | Export-CSV “C:\Temp\InActiveADUsers.CSV” –NoTypeInformation
I have given timespan for 120days and export the list into csv file.

Generate data seeding script using PowerShell and SSMS

Here I found a solution for the manual creation of the data seeding script. The manual solution allows me to select for which tables I want to generate the inserts
I would like to know if there is an option to run the same process via PowerShell?
So far I have managed how to create a SQL script which creates the Database schema seeder:
[System.Reflection.Assembly]::LoadWithPartialName('Microsoft.SqlServer.SMO') | out-null
$s = new-object ('Microsoft.SqlServer.Management.Smo.Server') "(localdb)\mssqlLocalDb"
$dbs=$s.Databases
#$dbs["HdaRoot"].Script()
$dbs["HdaRoot"].Script() | Out-File C:\sql-seeding\HdaRoot.sql
#Generate script for all tables
foreach ($tables in $dbs["HdaRoot"].Tables)
{
$tables.Script() + "`r GO `r " | out-File C:\sql-seeding\HdaRoot.sql -Append
}
however is there any similar way to generate the data seeding script?
Any ideas? Cheers
You can use the SMO scripter class. This will allow you to script the table creates as well as INSERT statements for the data within the tables.
In my example I'm directly targeting TempDB and defining an array of table names I want to script out rather than scripting out every table.
Scripter has a lot of options available, so I've only done a handful in this example - the important one for this task is Options.ScriptData. Without it you'll just get the schema scripts that you're already getting.
The EnumScript method at the end does the actual work of generating the scripts, outputting, and appending the script to the file designated in the options.
[System.Reflection.Assembly]::LoadWithPartialName('Microsoft.SqlServer.SMO') | out-null
## target file
$outfile = 'f:\scriptOutput.sql'
## target server
$s = new-object ('Microsoft.SqlServer.Management.Smo.Server') "localhost"
## target database
$db = $s.databases['tempdb']
## array of tables that we want to check
$tables = #('Client','mytable','tablesHolding')
## new Scripter object
$tableScripter = new-object ('Microsoft.SqlServer.Management.Smo.Scripter')($s)
##define options for the scripter
$tableScripter.Options.AppendToFile = $True
$tableScripter.Options.AllowSystemObjects = $False
$tableScripter.Options.ClusteredIndexes = $True
$tableScripter.Options.Indexes = $True
$tableScripter.Options.ScriptData = $True
$tableScripter.Options.ToFileOnly = $True
$tableScripter.Options.filename = $outfile
## build out the script for each table we defined earlier
foreach ($table in $tables)
{
$tableScripter.enumscript(#($db.tables[$table])) #enumscript expects an array. this is ugly, but it gives it what it wants.
}

Powershell process wait for SQL query to complete

I have a Powershell script that runs daily. The script is supposed to run a SQL query and create a file with the results.
Import-Module SqlPs
Invoke-Sqlcmd -InputFile "C:\SQL Queries\dailyexport1pm.sql" | Out-File -filepath "I:\HTPN Training and Workflow\Daily Epic Completion\$(get-date -f yyyy-MM-dd)dailyexport1pm.txt"
This used to work, however we recently added a large amount of data that causes the query to take up to 3.5 minutes. I do not have a strong understanding of powershell and need to have the out-file process run once the SQL query is complete. Any assistance would be appreciated.
The script outputs a blank txt file. When I check the task scheduler last run result, that the powershell script is the only action of, it says "The operation completed successfully. (0x0)"
I think there might be some error in the sql-file. Requesting you to try this once:
$Error.Clear()
try {
Import-Module SqlPs
Invoke-Sqlcmd -InputFile "C:\SQL Queries\dailyexport1pm.sql" -WarningAction SilentlyContinue -OutputSqlErrors $false
}
catch {
$Error | out-file -filepath "C:\temp\SqlLog.txt"
}
Note: Later if you see no error and the output is coming properly then you can pipe it to 'Out-File -filepath "I:\HTPN Training and Workflow\Daily Epic Completion\$(get-date -f yyyy-MM-dd)dailyexport1pm.txt" '
Hope it helps.