Powershell: ForEach loop error, not doing what i want - arrays

With my code I am trying to create a folder, then open a certain Excel file, edit it, and save it to the location that has been made via the function Dagcontrole_folders_maken . Currently i am using this ForEach in a ForEach loop. But it is not working. This is a simplified version of the complete code. The setup of the functions with the variables are neccesary.
Code to demonstrate problem:
$path_dagelijkse_controle = "C:\Users\Nick\Desktop\Test1",
"C:\Users\Nick\Desktop\Test2",
"C:\Users\Nick\Desktop\Test3"
$list_excels = 'C:\Users\nick\Desktop\Test1\kek3', #pad waar het excel bestand staat die geopend moet worden
'C:\Users\nick\Desktop\Test1\kek4',
'C:\Users\nick\Desktop\Test1\kek5'
function Dagcontrole_folders_maken ($huidige_folder) {
md -Path "$huidige_folder\2020" -Force # Makes all the neccessary folders
}
function Aanpassen_excel_dagcontrole ($path, $huidige_folder) {
$Excel = New-Object -ComObject excel.application
$Excel.visible = $True
$date_today= (get-date).DayOfWeek
$Workbook = $excel.Workbooks.open($path)
$workbook.SaveAs("$huidige_folder\$date_today")
$Excel.Quit()
Remove-Variable -Name excel
[gc]::collect()
[gc]::WaitForPendingFinalizers()
}
Foreach ($i in $path_dagelijkse_controle) {
Dagcontrole_folders_maken $i
Foreach ($a in $list_excels) {
Aanpassen_excel_dagcontrole $a $i
}
}
I'm getting errors on the following part: $workbook.SaveAs("$huidige_folder\$date_today"). Telling it does not have access to the file.
What I am trying to do is save the excel file in the directory that has just been made by the function Dagcontrole_folders_maken. I try this in the second loop with the data that comes from the $path_dagelijkse_controle list
The loop should do the following:
Dagcontrole_folder_maken
makes folder with location: "C:\Users\Nick\Desktop\Test1\2020"
Aanpassen_excel_dagcontrole
$Workbook = $excel.Workbooks.open('C:\Users\nick\Desktop\Test1\kek3')
$workbook.SaveAs('C:\Users\Nick\Desktop\Test1"\2020\20200806')
And after that is should do:
Dagcontrole_folder_maken
makes folder with location: "C:\Users\Nick\Desktop\Test2\2020"
Aanpassen_excel_dagcontrole
$Workbook = $excel.Workbooks.open('C:\Users\nick\Desktop\Test2\kek4')
$workbook.SaveAs('C:\Users\Nick\Desktop\Test2"\2020\20200806')
And then rest of the list
The complete code for reference:
$path_dagelijkse_controle = "C:\Users\Nick\Desktop\Test1",
"C:\Users\Nick\Desktop\Test2",
"C:\Users\Nick\Desktop\Test3"
$list_excels = 'C:\Users\nick\Desktop\Test1\kek3', #pad waar het excel bestand staat die geopend moet worden
'C:\Users\nick\Desktop\Test1\kek4',
'C:\Users\nick\Desktop\Test1\kek5'
function Dagcontrole_folders_maken ($huidige_folder) {
$Dagelijkse_controle = "Dagelijkse controle"
$datum_vandaag = $(Get-Date).toString('yyyy-MM-dd')
$jaar = $datum_vandaag.Substring(0,4)
$maand = $datum_vandaag.substring(5, 2)
$dag = (get-date).DayOfWeek
$folder_maand = Get-Date -UFormat "%m - %B"
md -Path "$huidige_folder\$jaar\$folder_maand\Dagelijks\$datum_vandaag" -Force # Makes all the neccessary folders
}
function Aanpassen_excel_dagcontrole ($path, $huidige_folder) {
#editing excel file
$Controle_mailbox_vrijdag = "Nora Remeeus"
$weekcontrole1 = "Maandag"
$weekcontrole2 = "Dinsdag"
$partimedag = "Woensdag"
$dagcontroleur_parttimedag = "Victor Wong"
$weekcontrole_persoon = "Nick Siegert"
$afwezig_mailboxcontrole = "Vrijdag"
$Excel = New-Object -ComObject excel.application
$Excel.visible = $False
$Workbook = $excel.Workbooks.open($path)
$Worksheet = $Workbook.WorkSheets.item("Uit te voeren werkzaamheden")
$worksheet.activate()
$workbook.ActiveSheet.Cells.Item(3,3) = Date
if ($dag -eq $partimedag) {
$workbook.ActiveSheet.Cells.Item(9,3) = $dagcontroleur_parttimedag
$workbook.ActiveSheet.Cells.Item(10,3) = $dagcontroleur_parttimedag
$workbook.ActiveSheet.Cells.Item(12,3) = $dagcontroleur_parttimedag
}
if (($dag -eq $weekcontrole1) -or ($dag -eq $weekcontrole2)) {
$workbook.ActiveSheet.Cells.Item(13,3) = $weekcontrole_persoon
}
if ($dag -eq $afwezig_mailboxcontrole) {
$workbook.ActiveSheet.Cells.Item(11,3) = $Controle_mailbox_vrijdag
}
$workbook.SaveAs("$huidige_folder\$jaar\$folder_maand\Dagelijks\$datum_vandaag\$Dagelijkse_controle $datum_vandaag") #Edit to save with Dagelijkse controle + datum_vandaag Hardcoded $huidige folder (eerste deel) oud: "$huidige_folder\$jaar\$folder_maand\Dagelijks\$datum_vandaag\$Dagelijkse_controle $datum_vandaag"
$Excel.Quit()
Remove-Variable -Name excel
[gc]::collect()
[gc]::WaitForPendingFinalizers()
}
Foreach ($i in $path_dagelijkse_controle) {
Dagcontrole_folders_maken $i
Foreach ($a in $list_excels) {
Aanpassen_excel_dagcontrole $a $i
}
}

You've got what appears to be a logic and syntax errors in your code.
If you set Excel to not viable, then you cannot set it as the active Window.
So, this...
$Excel.visible = $False
....
$worksheet.activate()
... should be this...
$Excel.visible = $True
You are running this function ...
Aanpassen_excel_dagcontrole
... in a Loop, but this function is opening and closing MSExcel.exe on each pass. This will cause issues because the startup and shutdown of MSOffice products take time, but your loop is not waiting for that.
You should only an Office app once, open, process, close files, and after all are processed, then close the MSOffice app used.
I'd suggest you remove this ...
$Excel.Quit()
Remove-Variable -Name excel
[gc]::collect()
[gc]::WaitForPendingFinalizers()
... from that function and make it your last entry in the script. So, this:
# Start MSExcel only once
$Excel = New-Object -ComObject excel.application
$Excel.visible = $True
function Aanpassen_excel_dagcontrole
{
[cmdletbinding(SupportsShouldProcess)]
Param
(
$path, $huidige_folder
)
# editing excel file
$Controle_mailbox_vrijdag = 'Nora Remeeus'
$weekcontrole1 = 'Maandag'
$weekcontrole2 = 'Dinsdag'
$partimedag = 'Woensdag'
$dagcontroleur_parttimedag = 'Victor Wong'
$weekcontrole_persoon = 'Nick Siegert'
$afwezig_mailboxcontrole = 'Vrijdag'
$Workbook = $excel.Workbooks.open($path)
$Worksheet = $Workbook.WorkSheets.item('Uit te voeren werkzaamheden')
$worksheet.activate()
$workbook.ActiveSheet.Cells.Item(3,3) = Date
if ($dag -eq $partimedag)
{
$workbook.ActiveSheet.Cells.Item(9,3) = $dagcontroleur_parttimedag
$workbook.ActiveSheet.Cells.Item(10,3) = $dagcontroleur_parttimedag
$workbook.ActiveSheet.Cells.Item(12,3) = $dagcontroleur_parttimedag
}
if (($dag -eq $weekcontrole1) -or ($dag -eq $weekcontrole2))
{$workbook.ActiveSheet.Cells.Item(13,3) = $weekcontrole_persoon}
if ($dag -eq $afwezig_mailboxcontrole)
{$workbook.ActiveSheet.Cells.Item(11,3) = $Controle_mailbox_vrijdag}
$workbook.SaveAs("$huidige_folder\$jaar\$folder_maand\Dagelijks\$datum_vandaag\$Dagelijkse_controle $datum_vandaag")
}
Foreach ($i in $path_dagelijkse_controle)
{
Dagcontrole_folders_maken $i
Foreach ($a in $list_excels)
{Aanpassen_excel_dagcontrole $a $i}
}
# Clean-Up
$Excel.Quit()
Remove-Variable -Name excel
[gc]::collect()
[gc]::WaitForPendingFinalizers()
Making this change should eliminate your concern here...
I'm getting errors on the following part:
$workbook.SaveAs("$huidige_folder$date_today"). Telling it does not
have access to the file.
... because this indicated, the file is still in use. You should always check for the file open/close before processing the next. Since OS and App processing speeds impact availability. AS well as check for the existence of folder or files before you try to use them.
So, modify your code to include error handling, i.e, if/then, try/catch, test-Path, etc.
Simple example check:
# File in use check
$ExcelFilePath = 'D:\Temp\FileData.xlsx'
try {[IO.File]::OpenWrite($ExcelFilePath).close()}
catch {Write-Warning -Message "$ExcelFilePath is in use by another process"}
# Results
<#
WARNING: D:\Temp\FileData.xlsx is in use by another process
#>

I ended up doing the following instead of ForEach in Foreach:
Foreach ($i in $path_dagelijkse_controle) {
Dagcontrole_folders_maken $i
}
foreach($i in 0..2){
Aanpassen_excel_dagcontrole $list_excels[$i] $path_dagelijkse_controle[$i]
Start-Sleep -s 15
}
The sleep function is there because i got a alot of random excel error, on random iterations. And this miraculouslyfixed the error.

Related

SMO to script just the database and it settings (not the objects in it)

I have put together a nice PowerShell script to script out the objects (tables, functions, sprocs etc) from a database, limiting it to the ones in a list.
But I am stuck trying to find a way to script the database itself. Each time I do that, it seems to try to script out the whole database (it is way to large for that to go well).
Assuming I have a $db variable that is a reference to my database, how can I use SMO to script out that database, creating it with the same Properties and DatabaseScopedConfigurations, but none of the actual objects in it?
Update:
For reference here is my current script. It takes a server and database name and will script out all the objects found in a file called DbObjectsList.txt (assuming they are in the database). But this does not actually make the database. The database I am running this on is a legacy one, and it has a bunch of odd options set. I would like to preserve those.
$serverName = "MyServerName"
$databaseName = "MyDbName"
$date_ = (date -f yyyyMMdd)
$path = ".\"+"$date_"
# Load the Sql Server Management Objects (SMO) and output to null so we don't show the dll details.
[System.Reflection.Assembly]::LoadWithPartialName('Microsoft.SqlServer.SMO') > $null
# Setup the scripting options
$scriptOptions = new-object ('Microsoft.SqlServer.Management.Smo.ScriptingOptions')
$scriptOptions.ExtendedProperties = $true
$scriptOptions.AnsiPadding = $true
$scriptOptions.ClusteredIndexes = $true
# Dri = Declarative Referential Integrity
$scriptOptions.DriAll = $true
$scriptOptions.Triggers = $true
$scriptOptions.NoCollation = $false
$scriptOptions.SchemaQualify = $true
$scriptOptions.ScriptSchema = $true
$scriptOptions.EnforceScriptingOptions = $true
$scriptOptions.SchemaQualifyForeignKeysReferences = $true
$scriptOptions.NonClusteredIndexes = $true
$scriptOptions.Statistics = $true
$scriptOptions.Permissions = $true
$scriptOptions.OptimizerData = $true
# get a reference to the database we are going to be scripting from
$serverInstance = New-Object ('Microsoft.SqlServer.Management.Smo.Server') $serverName
$db=$serverInstance.Databases | Where-Object {$_.Name -eq $databaseName}
$dbname = "$db".replace("[","").replace("]","")
$dbpath = "$path"+ "\"+"$dbname" + "\"
if ( !(Test-Path $dbpath))
{
$null=new-item -type directory -name "$dbname"-path "$path"
}
# Load the list of db objects we want to script.
$listPath = ".\DbObjectList.txt"
if ((Test-Path $listPath))
{
$dbListItems = Get-Content -Path $listPath
}
else
{
throw "Could not find DbObjectst.txt file (it should have a list of what to script)."
}
# Setup the output file, removing any existing one
$outFile = "$dbpath" + "FullScript.sql"
if ((Test-Path $outFile)){Remove-Item $outFile }
$typeDelimiter = "=========="
foreach ($dbListItem in $dbListItems)
{
# Let the caller know which one we are working on.
echo $dbListItem
if ($dbListItem.StartsWith($typeDelimiter))
{
# Pull the type out of the header
$startIndex = $typeDelimiter.Length;
$stopIndex = $dbListItem.LastIndexOf($typeDelimiter)
$type = $dbListItem.Substring($startIndex, $stopIndex - $startIndex).Trim()
continue;
}
if ($type -eq $null)
{
throw "Types not included DbObjectsList.txt. Add types before groups of objects, surrounded by " + $typeDelimiter
}
foreach ($dbObjectToScript in $db.$type)
{
$objName = "$dbObjectToScript".replace("[","").replace("]","")
$compareDbListItem = "$dbListItem".replace("[","").replace("]","")
if ($compareDbListItem -eq $objName)
{
"-- " + $dbListItem | out-File -Append $outFile
$dbObjectToScript.Script($scriptOptions)+"GO" | out-File -Append $outFile
}
}
}

Scripting DBs backup through Powershell

I have created a PowerShell script that takes the back up of entire structure of database. When it comes to jobs backup, I cannot find a possible solution to that.
$v = [System.Reflection.Assembly]::LoadWithPartialName('Microsoft.SqlServer.SMO')
if ((($v.FullName.Split(','))[1].Split('='))[1].Split('.')[0] -ne '9')
{
[System.Reflection.Assembly]::LoadWithPartialName('Microsoft.SqlServer.SMOExtended') | out-null
}
[System.Reflection.Assembly]:: LoadWithPartialName('Microsoft.SqlServer.SmoEnum') | out-null
set-psdebug -strict # catch a few extra bugs
$ErrorActionPreference = "stop"
$My = 'Microsoft.SqlServer.Management.Smo'
$srv = new-object ("$My.Server") $ServerName # attach to the server
foreach($sqlDatabase in $srv.databases)
{
$databaseName=$sqlDatabase.name
if ($databaseName.count)
{
$scripter = new-object ("$My.Scripter") $srv # create the scripter
$scripter.Options.ToFileOnly = $true
# we now get all the object types except extended stored procedures
# first we get the bitmap of all the object types we want
$all =[long]
[Microsoft.SqlServer.Management.Smo.DatabaseObjectTypes]:: all -bxor
[Microsoft.SqlServer.Management.Smo.DatabaseObjectTypes]:: ExtendedStoredProcedure
# and we store them in a datatable
$d = new-object System.Data.Datatable
# get everything except the servicebroker object, the information schema and system views
$d = $srv.databases[$databaseName].EnumObjects([long]0x1FFFFFFF -band $all) | Where-Object {$_.Schema -ne 'sys'-and $_.Schema "information_schema"
#Saving it in a directory
}
}
This scripts takes the back up of the db but take the structural back up of msdb. I studied Microsoft.SqlServer.SMO that says it has a job server agent and job collection function but it doesn't seem to work.
For jobs, use the JobServer.Jobs collection. You can similarly script other server-level objects.
Below is an example.
$jobsCollection = $srv.JobServer.Jobs
$scriptingOptions = New-Object Microsoft.SqlServer.Management.Smo.ScriptingOptions
$scriptingOptions.IncludeIfNotExists = $true
$scriptingOptions.AppendToFile = $false
$scriptingOptions.ToFileOnly = $true
foreach ($job in $jobsCollection) {
Write-Host "Scripting $($job.Name)"
$scriptingOptions.FileName = "C:\ScriptFolder\Jobs.sql"
$job.Script($scriptingOptions)
$scriptingOptions.AppendToFile = $true
}
Although the answer given by Dan helped me but it wasn't creating a script in the folders. It was just creating folders with the jobs names. So, I did something like this :
foreach($sqlDatabase in $srv.JobServer.Jobs)
{ $databaseName=$sqlDatabase.name
write-host("I am her '$databaseName' ");
$scripter = new-object ("$My.Scripter") $srv # create the scripter
$scripter.Options.ToFileOnly = $true
$d = new-object System.Data.Datatable
$d=$srv.JobServer.Jobs[$databaseName]
$d| FOREACH-OBJECT {
trap [System.Management.Automation.MethodInvocationException]{
write-host ("ERROR: " + $_) -Foregroundcolor Red; Continue
}
# for every object we have in the datatable.
$SavePath="$($DirectoryToSaveTo)\$($ServerName)\$($databaseName)\$($_.DatabaseObjectTypes)"
# create the directory if necessary (SMO doesn't).
if (!( Test-Path -path $SavePath )) # create it if not existing
{Try { New-Item $SavePath -type directory | out-null }
Catch [system.exception]{
Write-Error "error while creating '$SavePath' $_"
return
}
}
# tell the scripter object where to write it
$scripter.Options.Filename = "$SavePath\$($_.name -replace '[\\\/\:\.]','-').sql";
# Create a single element URN array
$UrnCollection = new-object ('Microsoft.SqlServer.Management.Smo.urnCollection')
$URNCollection.add($_.urn)
# and write out the object to the specified file
$scripter.script($URNCollection)
}
}

Powershell Write-Host showing only dataTable name instead of data

I'm trying to write a Powershell script that executes a SQL query contained in a .sql file
Function RunSQLScript ($connstring, $filePath)
{
$query = get-content $filePath;
$DTSet = New-Object System.Data.DataSet;
$Conn=New-Object System.Data.SQLClient.SQLConnection $connstring;
$Conn.Open();
try
{
$DataCmd = New-Object System.Data.SqlClient.SqlCommand;
$MyQuery = $query;
$DataCmd.CommandText = $MyQuery;
$DataCmd.Connection = $Conn;
$DAadapter = New-Object System.Data.SqlClient.SqlDataAdapter;
$DAadapter.SelectCommand = $DataCmd;
$DAadapter.Fill($DTSet) | Out-Null;
for ($i = 0; $i -lt $DTSet.Tables.Count; $i++) {
Write-Host $DTSet.Tables[$i];
}
}
finally
{
$Conn.Close();
$Conn.Dispose();
}
return $DTSet;
}
The internal Write-Host is showing the DataTable name instead of the DataRows.
If I manually create a DataSet with a DataTable in Powershell Console, Write-Host shows me the data in the DataTable rows, so I can't really figure out why it is not doing that in the previous script.
Can you give me some clues on how to show the data contained in the datatables instead of the table names?
Thank you
This piece of code was quite helpful for me, posting it here if anybody needs it.
for ($i = 0; $i -lt $DTSet.Tables.Count; $i++) {
$DTSet.Tables[$i] | format-table | out-host
}
That produces a nice table-like output on screen.

Powershell Function import multiple CSVs into Excel workbook

Ok, time to start this question over. I found the following script http://blogs.technet.com/b/heyscriptingguy/archive/2010/09/09/copy-csv-columns-to-an-excel-spreadsheet-by-using-powershell.aspx
My question is how would I get powershell to loop that script for any number of CSV files. The speed of the script is not important. I've received some answers of which, in some way, have their problems. Using the Technet script provides the correct output.
I have come up with this but am having a tough time getting the code to loop through multiple CSV files.
Function Excel-Stuff {
[cmdletBinding()]
Param([Parameter(ValueFromPipeline=$true)][string]$junk)
$excel.cells.item(1,1) = "Server"
$excel.cells.item(1,2) = "Rack"
$excel.cells.item(1,3) = "Environment"
$excel.cells.item(1,4) = "RebootTime"
$excel.cells.item(1,5) = "Schedule"
$i = 2
$processes = Import-Csv 'C:\Monday.csv'
foreach ($process in $processes){
$excel.cells.item($i,1) = $process.Server
$excel.cells.item($i,2) = $process.Rack
$excel.cells.item($i,3) = $process.Environment
$excel.cells.item($i,4) = $process.RebootTime
$excel.cells.item($i,5) = $process.Schedule
$i++
} #end foreach process
$autofit = $Global:worksheet.UsedRange
$autofit.EntireColumn.AutoFit() | Out-Null
}#End Function.
$Excel = New-Object -ComObject excel.application
$workbook = $Excel.workbooks.add(1)
$Global:worksheet = $workbook.WorkSheets.Item(1)
$Global:worksheet.Name='Monday'
Excel-Stuff
$Excel.visible = $True
Ok, so let's not do this the hard way. Copy/paste is your friend, and you can do it easily here.
You have Monday-Friday tabs, and I assume 7 CSV files. Loop this thing 7 times, and in each loop Create a tab, name it, then copy the entire CSV, convert it to a tab delimited CSV, and pipe it to CLIP.exe. Then just select A1 on the current sheet and paste. Start the next loop with the next CSV file.
$path = "c:\tmp\mytest.xlsx"
$day = #("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday")
$Excel = New-Object -ComObject excel.application
$Excel.visible = $false
$workbook = $Excel.workbooks.add(1)
$day | %{
$processes = Import-Csv -Path "D:\Scripts\work\$_.csv"
$worksheet = $workbook.WorkSheets.add()
$processes | ConvertTo-Csv -Delimiter "`t" -NoTypeInformation | Clip.exe
$worksheet.select()
$worksheet.Name = $_
[void]$Excel.ActiveSheet.Range("A1:A1").Select()
[void]$Excel.ActiveCell.PasteSpecial()
[void]$worksheet.UsedRange.EntireColumn.AutoFit()
}
#Clean up extra sheets
$Excel.DisplayAlerts = $false
$workbook.Worksheets|?{$day -notcontains $_.name}|%{$_.Delete()}
$Excel.DisplayAlerts = $true
[void]$Excel.ActiveSheet.Range("A1:A1").Select()
$workbook.saveas($path)
$Excel.Quit()
Remove-Variable -Name excel
[gc]::collect()
[gc]::WaitForPendingFinalizers()
Then your only concern is that the CSV files are in the right order. If you named your CSV files Monday.csv, Tuesday.csv etc this could probably be simpler, but so long as they're named so that Monday's is the first, and it goes in alpha-numeric order you'll be just fine with that code.
(Edited to reflect comment suggestions for single cell selection before saving and changed -notin to -notcontains)

Sql Server Script data: SMO.Scripter not working when output to file

I get this error message when I run the Powershell script at the bottom:
Exception calling "EnumScript" with "1" argument(s): "Script failed for Table 'dbo.Product'. "
At :line:48 char:35
+ foreach ($s in $scripter.EnumScript <<<< ($tbl)) { write-host $s }
However, when I comment out the output_file line
#$output_file="C:\Product.sql"
(which won't set the Scripter options to write to file), it works fine and outputs the INSERT statments to the console.
Here's the failing script, is there something I'm missing?
# Script INSERTs for given table
param
(
[string] $server,
[string] $database,
[string] $schema,
[string] $table,
[string] $output_file
)
$server="devdidb02"
$database="EPCTrunk_EPC"
$schema="dbo"
$table="Product"
$output_file="C:\Product.sql"
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SMO") | out-null
$srv = New-Object "Microsoft.SqlServer.Management.SMO.Server" $server
$db = New-Object ("Microsoft.SqlServer.Management.SMO.Database")
$tbl = New-Object ("Microsoft.SqlServer.Management.SMO.Table")
$scripter = New-Object ("Microsoft.SqlServer.Management.SMO.Scripter") ($server)
# Get the database and table objects
$db = $srv.Databases[$database]
$tbl = $db.tables | Where-object {$_.schema -eq $schema-and$_.name -eq $table}
# Set scripter options to ensure only data is scripted
$scripter.Options.ScriptSchema = $false;
$scripter.Options.ScriptData = $true;
#Exclude GOs after every line
$scripter.Options.NoCommandTerminator = $true;
if ($output_file -gt "")
{
$scripter.Options.FileName = $output_file
$scripter.Options.ToFileOnly = $true
}
# Output the script
foreach ($s in $scripter.EnumScript($tbl)) { write-host $s }
I ran both yours and Keith's and it looks like the issue is in the path you are setting for the file. I was able to reproduce your error. You were using $output_file="C:\Product.sql". Then I changed the path to: $output_file="$home\Product.sql" it ran just fine and gave me the file.
I am guessing that the reason for this is that I don't have permission to write to c:\ which may be the problem you are having.
BTW - my home dir in this case for me is my user folder for my login so I was able to find it there.
FWIW I'm not able to repro the error you see using the AdventureWorks DB. The following generates the foo.sql file without any errors:
Add-Type -AssemblyName ('Microsoft.SqlServer.Smo, Version=10.0.0.0, ' + `
'Culture=neutral, PublicKeyToken=89845dcd8080cc91')
$serverName = '.\SQLEXPRESS'
$smo = new-object Microsoft.SqlServer.Management.Smo.Server $serverName
$db = $smo.Databases['AdventureWorks']
$tbl = $db.Tables | Where {$_.Schema -eq 'Production' -and `
$_.Name -eq 'Product'}
$output_file = "$home\foo.sql"
$scripter = new-object Microsoft.SqlServer.Management.Smo.Scripter $serverName
$scripter.Options.ScriptSchema = $false;
$scripter.Options.ScriptData = $true;
$scripter.Options.NoCommandTerminator = $true;
if ($output_file -gt "")
{
$scripter.Options.FileName = $output_file
$scripter.Options.ToFileOnly = $true
}
# Output the script
foreach ($s in $scripter.EnumScript($tbl)) { write-host $s }

Resources