Copy SQL Server database using PowerShell script in mixed mode - sql-server

I would like to create a SQL Server database using a PowerShell script using username and password. I have used this script:
$SQLInstanceName = "(localdb)\MSSQLLocalDB"
$Server = New-Object -TypeName Microsoft.SqlServer.Management.Smo.Server -ArgumentList $SQLInstanceName
# This sets the connection to mixed-mode authentication
$Server.ConnectionContext.LoginSecure=$false;
# This sets the login name
$Server.ConnectionContext.set_Login("test");
# This sets the password
$Server.ConnectionContext.set_Password("*******")
$SourceDBName = "##SourceDBName##"
$SourceDB = $Server.Databases[$SourceDBName]
$CopyDBName = "##DestDBName##"
$CopyDB = New-Object -TypeName Microsoft.SqlServer.Management.SMO.Database -ArgumentList $Server , $CopyDBName
$CopyDB.Create()
$ObjTransfer = New-Object -TypeName Microsoft.SqlServer.Management.SMO.Transfer -ArgumentList $SourceDB
$ObjTransfer.CopyAllTables = $true
$ObjTransfer.Options.WithDependencies = $true
$ObjTransfer.Options.ContinueScriptingOnError = $true
$ObjTransfer.DestinationDatabase = $CopyDBName
$ObjTransfer.DestinationServer = $Server.Name
$ObjTransfer.DestinationLoginSecure = $true
$ObjTransfer.CopySchema = $true
$ObjTransfer.ScriptTransfer() enter code here
$ObjTransfer.TransferData()
But I get this error:
SetParent failed for Database 'coupadb_master_TestClient'. "
at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)

Related

Copy SQL Server database with PowerShell script

I want to copy database within the same server to have a test database using the under code but it works fine the first run and then an error occur .I think that was a problem of the name of the destination database because i change the name of destination it works also .How can I proceed to override the destination database without renaming the destination.
Import-Module SQLPS -DisableNameChecking
#your SQL Server Instance Name
$SQLInstanceName = "DESKTOP-444"
$Server = New-Object -TypeName Microsoft.SqlServer.Management.Smo.Server -ArgumentList $SQLInstanceName
#provide your database name which you want to copy
$SourceDBName = "test"
#create SMO handle to your database
$SourceDB = $Server.Databases[$SourceDBName]
#create a database to hold the copy of your source database
$CopyDBName = "$($SourceDBName)_copy"
$CopyDB = New-Object -TypeName Microsoft.SqlServer.Management.SMO.Database -ArgumentList $Server , $CopyDBName
$CopyDB.Create()
#Use SMO Transfer Class by specifying source database
#you can specify properties you want either brought over or excluded, when the copy happens
$ObjTransfer = New-Object -TypeName Microsoft.SqlServer.Management.SMO.Transfer -ArgumentList $SourceDB
$ObjTransfer.CopyAllTables = $true
$ObjTransfer.Options.WithDependencies = $true
$ObjTransfer.Options.ContinueScriptingOnError = $true
$ObjTransfer.DestinationDatabase = $CopyDBName
$ObjTransfer.DestinationServer = $Server.Name
$ObjTransfer.DestinationLoginSecure = $true
$ObjTransfer.CopySchema = $true
#if you wish to just generate the copy script
#just script out the transfer
$ObjTransfer.ScriptTransfer()
#When you are ready to bring the data and schema over,
#you can use the TransferData method
$ObjTransfer.TransferData()
I was able to run your code multiple times without any issues. The following is the slightly cleaned-up version (structural changes):
Import-Module SQLPS -DisableNameChecking
$SQLInstanceName = "(local)"
$SourceDBName = "sandbox"
$CopyDBName = "${SourceDBName}_copy"
$Server = New-Object -TypeName 'Microsoft.SqlServer.Management.Smo.Server' -ArgumentList $SQLInstanceName
$SourceDB = $Server.Databases[$SourceDBName]
$CopyDB = New-Object -TypeName 'Microsoft.SqlServer.Management.SMO.Database' -ArgumentList $Server , $CopyDBName
$CopyDB.Create()
$ObjTransfer = New-Object -TypeName Microsoft.SqlServer.Management.SMO.Transfer -ArgumentList $SourceDB
$ObjTransfer.CopyAllTables = $true
$ObjTransfer.Options.WithDependencies = $true
$ObjTransfer.Options.ContinueScriptingOnError = $true
$ObjTransfer.DestinationDatabase = $CopyDBName
$ObjTransfer.DestinationServer = $Server.Name
$ObjTransfer.DestinationLoginSecure = $true
$ObjTransfer.CopySchema = $true
$ObjTransfer.ScriptTransfer()
$ObjTransfer.TransferData()
What error did you get?
The one thing I noticed. If the cloned database already exists, the script will fail. You should get an exception up around the $CopyDB.Create() statement and probably another one when you go to copy the objects to the cloned database.
I'd either drop the database if it exists, or abort script execution if it exists.
EDIT
I was told to use the module SqlServer instead of the module SQLPS, because the latter had long been deprecated. And immediately after I have made the change, I noticed that it was now possible to create databases from a Microsoft.SqlServer.Management.SMO.Transfer object, which I was not managing before. I don't understand why, and it might even be unrelated and I was just lucky. The SqlServer package can be installed through the following command:
Install-Module -Name SqlServer -AllowClobber
Thus I am updating my answer with the working code, which is more readable, more elegant and more performant than my previous answer (at the bottom of this post).
$SQLInstanceName = $env:servername
$SourceDBName = $env:databasename
$SQLUser = $env:adminlogin
$SQLPassword = $env:adminPassword
Import-Module SqlServer -DisableNameChecking
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo") | Out-Null;
Function IsNullOrEmpty([string]$val){
if ($val -eq $null -or $val -eq '') { $true }
else{ $false }
}
If (IsNullOrEmpty($SQLInstanceName)) {
$SQLInstanceName = $args[0]
}
If (IsNullOrEmpty($SourceDBName)) {
$SourceDBName = $args[1]
}
If (IsNullOrEmpty($SQLUser)) {
$SQLUser = $args[2]
}
If (IsNullOrEmpty($SQLPassword)) {
$SQLPassword = $args[3]
}
Try {
$Server = New-Object Microsoft.SqlServer.Management.Smo.Server($SQLInstanceName)
$DestinationDBName = "${SourceDBName}.Staging"
$SQLSecurePassword = ConvertTo-SecureString $SQLPassword -AsPlainText -Force
$Server.ConnectionContext.LoginSecure = $false
$Server.ConnectionContext.set_Login($SQLUser)
$Server.ConnectionContext.set_SecurePassword($SQLSecurePassword)
$SourceDB = $Server.Databases[$SourceDBName]
$ObjTransfer = New-Object Microsoft.SqlServer.Management.SMO.Transfer ($SourceDB)
$CopyDB = New-Object Microsoft.SqlServer.Management.SMO.Database ($Server, $DestinationDBName)
$CopyDB.Create()
# $ObjTransfer.CopyData = $false - Uncomment this line so that data is not copied across
$ObjTransfer.CopySchema = $true
$ObjTransfer.CopyAllTables = $true
$ObjTransfer.CopyAllDatabaseTriggers = $true
$ObjTransfer.Options.WithDependencies = $true
$ObjTransfer.Options.ContinueScriptingOnError = $true
$ObjTransfer.DestinationDatabase = $DestinationDBName
$ObjTransfer.DestinationServer = $SQLInstanceName
$ObjTransfer.DestinationPassword = $SQLPassword
$ObjTransfer.DestinationLogin = $SQLUser
$ObjTransfer.DestinationLoginSecure = $false
$ObjTransfer.TransferData()
}
Catch [System.Exception] {
# $_ is set to the ErrorRecord of the exception
if ($_.Exception.InnerException) {
Write-Error $_.Exception.InnerException.Message
} else {
Write-Error $_.Exception.Message
}
if($Server.Databases.Name -like $DestinationDBName) {
Write-Host "Dropping cloned database..."
# Call drop-db.ps1 to delete the stagingDB
Invoke-Command { .\drop-db.ps1 $SQLInstanceName $DestinationDBName $SQLUser $SQLPassword }
}
}
Finally {
if($Server) {
$Server.ConnectionContext.Disconnect()
}
}
I was having a similar error implementing this. Tried literally everything, it just wouldn't work. What did work for me, was generating a script through the ScriptTransfer method, create the new database and then apply the script to the new database through Invoke-SqlCmd. The code I am sharing can be invoked locally, by passing 4 arguments to the script in the following order:
Server Name
Database Name
Login
Password
And it can also be used on a pipeline. I am using it on Azure DevOps by setting those 4 arguments through a group variable.
I am appending .Staging to the source database name, and that's the name I give to the new database. If something fails along the way, I delete the new database, in case it has already been created.
$SQLInstanceName = $env:servername
$SourceDBName = $env:databasename
$SQLUser = $env:adminlogin
$SQLPassword = $env:adminPassword
Import-Module SQLPS -DisableNameChecking
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo") | Out-Null;
Function IsNullOrEmpty([string]$val){
if ($val -eq $null -or $val -eq '') { $true }
else{ $false }
}
If (IsNullOrEmpty($SQLInstanceName)) {
$SQLInstanceName = $args[0]
}
If (IsNullOrEmpty($SourceDBName)) {
$SourceDBName = $args[1]
}
If (IsNullOrEmpty($SQLUser)) {
$SQLUser = $args[2]
}
If (IsNullOrEmpty($SQLPassword)) {
$SQLPassword = $args[3]
}
Try {
$Server = New-Object Microsoft.SqlServer.Management.Smo.Server($SQLInstanceName)
}
Catch [System.Exception] {
# $_ is set to the ErrorRecord of the exception
if ($_.Exception.InnerException) {
Write-Error $_.Exception.InnerException.Message
} else {
Write-Error $_.Exception.Message
}
}
Finally {
Try {
$StagingDBName = "${SourceDBName}.Staging"
$SQLSecurePassword = ConvertTo-SecureString $SQLPassword -AsPlainText -Force
$Server.ConnectionContext.LoginSecure = $false
$Server.ConnectionContext.set_Login($SQLUser)
$Server.ConnectionContext.set_SecurePassword($SQLSecurePassword)
$CreationScriptOptions = New-Object Microsoft.SqlServer.Management.SMO.ScriptingOptions
$CreationScriptOptions.ExtendedProperties= $true
$CreationScriptOptions.DRIAll= $true
$CreationScriptOptions.Indexes= $true
$CreationScriptOptions.Triggers= $true $CreationScriptOptions.ScriptBatchTerminator = $true
$CreationScriptOptions.IncludeHeaders = $true;
$CreationScriptOptions.ToFileOnly = $true
$CreationScriptOptions.IncludeIfNotExists = $true
$SourceDB = $Server.Databases[$SourceDBName]
$ObjTransfer = New-Object Microsoft.SqlServer.Management.SMO.Transfer ($SourceDB)
$ObjTransfer.options=$CreationScriptOptions # tell the transfer object of our preferences
$FilePath = Join-Path $PSScriptRoot "$($StagingDBName).sql"
$ObjTransfer.Options.Filename = $FilePath;
$ObjTransfer.ScriptTransfer()
$CopyDB = New-Object Microsoft.SqlServer.Management.SMO.Database ($Server, $StagingDBName)
$CopyDB.Create()
$auth=#{UserName=$SQLUser;Password=$SQLPassword}
Invoke-SqlCmd -InputFile $FilePath -ServerInstance $Server -Database $StagingDBName #Auth -Verbose
}
Catch [System.Exception] {
# $_ is set to the ErrorRecord of the exception
if ($_.Exception.InnerException) {
Write-Error $_.Exception.InnerException.Message
} else {
Write-Error $_.Exception.Message
}
if($Server.Databases.Name -like $StagingDBName) {
Write-Host "Dropping staging database..."
$auth=#{UserName=$SQLUser;Password=$SQLPassword}
Invoke-SqlCmd -ServerInstance $Server #Auth `
-Query "IF EXISTS (SELECT name FROM master.dbo.sysdatabases WHERE name ='$($StagingDBName)') `
BEGIN `
ALTER DATABASE [$($StagingDBName)] SET SINGLE_USER WITH ROLLBACK IMMEDIATE; `
DROP DATABASE [$($StagingDBName)]; `
END;" `
-Verbose
}
}
Finally {
$Server.ConnectionContext.Disconnect()
}
}

Terminated Users script - adapt single-run script to run for multiple users?

I don't want to run script for each terminated user, I assume I need to use do while loop for this so the it will continually loop over and over again until the ESC option.
I have been trying to do this in powershell, but I am new to it and am still learning. Do you have any idea?
$wshell = New-Object -ComObject Wscript.Shell
$wshell.Popup("Please enter in your Domain Admin credentials. Please remember it should be in the form of DOMAIN\username.",0,"Credentials Needed!",0x0)
$creds = Get-Credential
$PSDefaultParameterValues = #{"*-AD*:Credential"=$creds}
#Here we create the connection to the exchange server. Edit with your mailserver info
$ExchangeSession = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri http://**editmemithyourwebmailservername**/PowerShell
Import-PSSession $ExchangeSession
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[void] [System.Windows.Forms.Application]::EnableVisualStyles()
$objForm = New-Object System.Windows.Forms.Form
$objForm.Text = "Terminated Employee Process Form"
$objForm.Size = New-Object System.Drawing.Size(500,400)
$objForm.StartPosition = "CenterScreen"
$objForm.MaximizeBox = $False
$objForm.KeyPreview = $True
$objForm.Add_KeyDown({if ($_.KeyCode -eq "Enter")
{$userinput=$UserTextBox.Text;$forwardemail=$ForwardingTextBox.Text;$ticketnumber=$TicketTextBox.Text;$disableuser=$DisableUserCheckbox.Checked;$objForm.Close()}})
$objForm.Add_KeyDown({if ($_.KeyCode -eq "Escape")
{$objForm.Close()}})
$Font = New-Object System.Drawing.Font("Verdana",8,[System.Drawing.FontStyle]::Bold)
#$objForm.Font = $Font
#VERSION NUMBER
$VersionLabel = New-Object System.Windows.Forms.Label
$VersionLabel.Location = New-Object System.Drawing.Size(450,10)
$VersionLabel.Size = New-Object System.Drawing.Size(120,20)
$VersionLabel.Font = $Font
$VersionLabel.Text = "V1"
$objForm.Controls.Add($VersionLabel)
#OK AND CANCEL BUTTONS
$OKButton = New-Object System.Windows.Forms.Button
$OKButton.Location = New-Object System.Drawing.Size(75,320)
$OKButton.Size = New-Object System.Drawing.Size(75,23)
$OKButton.Text = "OK"
$OKButton.Add_Click({$userinput=$UserTextBox.Text;$ticketnumber=$TicketTextBox.Text;$forwardemail=$ForwardingTextBox.Text;$disableuser=$DisableUserCheckbox.Checked;$objForm.Close()})
$objForm.Controls.Add($OKButton)
#USERNAME LABEL
$UserLabel = New-Object System.Windows.Forms.Label
$UserLabel.Location = New-Object System.Drawing.Size(10,20)
$UserLabel.Size = New-Object System.Drawing.Size(280,20)
$UserLabel.Text = "Username of Terminated Employee"
$objForm.Controls.Add($UserLabel)
#USERNAME TEXT BOX
$UserTextBox = New-Object System.Windows.Forms.TextBox
$UserTextBox.Location = New-Object System.Drawing.Size(10,40)
$UserTextBox.Size = New-Object System.Drawing.Size(180,20)
$objForm.Controls.Add($UserTextBox)
#DISABLE USER CHECKBOX CONTROL
$DisableUserCheckbox = New-Object System.Windows.Forms.Checkbox
$DisableUserCheckbox.Location = New-Object System.Drawing.Size(220,30)
$DisableUserCheckbox.Size = New-Object System.Drawing.Size(120,40)
$DisableUserCheckbox.Text = "Disable The User?"
$objForm.Controls.Add($DisableUserCheckbox)
#FORWARD EMAIL LABEL
$FowardEmailLabel = New-Object System.Windows.Forms.Label
$FowardEmailLabel.Location = New-Object System.Drawing.Size(10,80)
$FowardEmailLabel.Size = New-Object System.Drawing.Size(280,20)
$FowardEmailLabel.Text = "Forward Email to Manager? If Yes, Type In Email Address"
$objForm.Controls.Add($FowardEmailLabel)
#FORWARD EMAIL TEXT BOX
$ForwardingTextBox = New-Object System.Windows.Forms.TextBox
$ForwardingTextBox.Location = New-Object System.Drawing.Size(10,100)
$ForwardingTextBox.Size = New-Object System.Drawing.Size(180,40)
$objForm.Controls.Add($ForwardingTextBox)
#ENTER TICKET NUMBER TEXT LABEL
$TicketLabel = New-Object System.Windows.Forms.Label
$TicketLabel.Location = New-Object System.Drawing.Size(10,150)
$TicketLabel.Size = New-Object System.Drawing.Size(80,20)
$TicketLabel.Text = "Issue Number"
$objForm.Controls.Add($TicketLabel)
$TicketTextBox = New-Object System.Windows.Forms.TextBox
$TicketTextBox.Location = New-Object System.Drawing.Size(10,170)
$TicketTextBox.Size = New-Object System.Drawing.Size(40,250)
$objForm.Controls.Add($TicketTextBox)
#CANCEL BUTTONS
$CancelButton = New-Object System.Windows.Forms.Button
$CancelButton.Location = New-Object System.Drawing.Size(350,320)
$CancelButton.Size = New-Object System.Drawing.Size(75,23)
$CancelButton.Text = "Cancel"
$CancelButton.Add_Click({$objForm.Close(); $cancel = $true})
$objForm.Controls.Add($CancelButton)
$objForm.Topmost = $True
$objForm.Add_Shown({$objForm.Activate()})
[void] $objForm.ShowDialog()
if ($cancel) {return}
#$OKButton.Add_Click({$userinput=$UserTextBox.Text;$ticketnumber=$TicketTextBox.Text;$forwardemail=$ForwardingTextBox.Text;$disableuser=$DisableUserCheckbox.Checked;$objForm.Close()})
#$CancelButton.Add_Click({$objForm.Close()})
#COMMON GLOBAL VARIABLES
$disableusercheckbox=$DisableUserCheckbox.Checked
$userinput=$UserTextBox.Text
$forwardemail=$ForwardingTextBox.Text
$ticketnumber=$TicketTextBox.Text
$Month = Get-Date -format MM
$Day = Get-Date -format dd
$Year = Get-Date -format yyyy
If ($OKButton.Add_Click) {
########
#ACTIVE DIRECTORY ACTIONS
#########
#DISABLE THE USER
If ($disableusercheckbox -eq $true)
{
Disable-ADAccount -Identity $userinput
$disabled = $userinput + " has been disabled"
} else {
$notdisabled = $userinput + " has not been disabled at this time"
}
#GETS ALL GROUPS USER WAS PART OF BEFORE BLOWING THEM OUT
$User = $userinput
$List=#()
$Groups = Get-ADUser -Identity $User -Properties * | select -ExpandProperty memberof
foreach($i in $Groups){
$i = ($i -split ',')[0]
$List += "`r`n" + ($i -creplace 'CN=|}','')
}
#BLOW OUT GROUPS OF USER EXCEPT DOMAIN USERS
(get-aduser $userinput -properties memberof).memberof|remove-adgroupmember -member $userinput -Confirm:$False
#SETS THE USERS TITLE,COMPANY/MANAGER TO DISABLED
set-aduser -identity $userinput -title "CompanyName - Disabled $Month/$Day/$Year"
set-aduser -identity $userinput -company $null
set-aduser -identity $userinput -manager $null
set-aduser -identity $userinput -department $null
set-aduser -identity $userinput -description "CompanyName - Disabled $Month/$Day/$Year per Issue# $ticketnumber"
#CHANGES THE USERS PASSWORD
$newpwd = ConvertTo-SecureString -String "G00dBye#1234" -AsPlainText –Force
Set-ADAccountPassword $userinput –NewPassword $newpwd -Reset
#MOVES THE USER TO DISABLED USERS
Get-ADUser -Filter { samAccountName -like $userinput } | Move-ADObject –TargetPath "OU=Disabled Users,OU=User Accounts,DC=domain,DC=com"
#HIDES USER FROM GLOBAL ADDRESS BOOK and configures forwarding
Set-Mailbox -Identity $userinput -ForwardingAddress $forwardemail -HiddenFromAddressListsEnabled $true
#REMOVES THE SESSION
Remove-PSsession $ExchangeSession
Start-Sleep -s 2
}
Form text boxes are going to be tricky to handle multiple users. So instead, use a CSV file as input file with the username and ticketnumber as headers.
$CSVList = Import-csv C:\Temp\InputFile.csv
Use a Foreach loop to loop through each line in the CSV.
Foreach ($Line.Username in $CSVList)
{
#your termination code goes here
#if at any point you need to use the ticket number for this user
$TicketNo = $Line.TicketNumber
#This is the Header you used in the csv file.
}
For Display, create an object table (much like a csv file) and show it using a Datagridview or the more simpler Out-Gridview instead of labels so you can support displaying multiple users. (Out-Gridview will create its own window though)

Connect to SQL Server Database from PowerShell when calling function from function

I am using PowerShell scripts. I have some senior
filter $server and $instance name from .txt file.
Use the $server and $instance in to the 2 function for connect to SQL Server
My .txt file code are as below
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SMO") | Out-Null
# Get our list of target servers from the local servers.txt file(Need
$servers = Get-Content 'mirroringserver.txt'
foreach ($prcs in $servers) {
# The first entry in the file is the machine name, the second is the instance name so separate them
#$srvc = $prcs.Split($prcs, "\r\n")
# $ServerName = $prcs
$srvc = $prcs.Split('\')
$servers = $srvc[0]
$instance = $srvc[1]
GetConnectionString $servers $instance
# Ping the machine to see if it's on the network
$results = gwmi -query "select StatusCode from Win32_PingStatus where Address = '$servers'"
$responds = $false
foreach ($result in $results) {
# If the machine responds break out of the result loop and indicate success
if ($result.StatusCode -eq 0) {
$responds = $true
break
}
}
if ($responds) {
# Check to see if a directory exists for this machine, if not create one
if (!(Test-Path -Path .\$servers)) {
New-Item .\$servers\ -Type Directory
}
# Get the server info in the first function and the instance info in the second
#mirroring $servers $instance
getInsertServerStatus $servers $instance
} else {
# Let the user know we couldn't connect to the server
Write-Output "$servers does not respond"
}
}
function GetConnectionString([string]$svr, [string]$inst) {
return "Server=$svr\$inst;Database=master;Integrated Security=True;"
}
This is my function 1:
function mirroring(
$svr,
$inst,
[string] $datastore,
[string] $datastore1,
[string] $datastore2,
[string] $datastore3,
[string] $datastore4,
[string] $datastore5,
[string] $datastore6,
[string] $datastore7
) {
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = GetConnectionString
$SqlConnection.Open()
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.CommandText = " SELECT db_name(sd.[database_id])AS [Database Name]
,sd.mirroring_state AS [Mirror State Number]
,sd.mirroring_state_desc AS [Mirror State]
,sd.mirroring_partner_name AS [Partner Name]
,sd.mirroring_role_desc AS [Mirror Role]
,sd.mirroring_safety_level_desc AS [Safety Level]
,sd.mirroring_witness_name AS [Witness]
,sd.mirroring_connection_timeout AS [Timeout(sec)]
FROM sys.database_mirroring AS sd
WHERE mirroring_guid IS NOT null
ORDER BY [Database Name];"
$SqlCmd.Connection = $SqlConnection
$SqlAdapter = New-Object System.Data.SqlClient.SqlDataAdapter
$SqlAdapter.SelectCommand = $SqlCmd
$DataSet = New-Object System.Data.DataSet
$SqlAdapter.Fill($DataSet)
$DataSet.Tables[0]
$SqlConnection.Close()
$datastore = $DataSet.Tables[0].Rows[0][0]
$datastore1 = $DataSet.Tables[0].Rows[0][1]
$datastore2 = $DataSet.Tables[0].Rows[0][2]
$datastore3 = $DataSet.Tables[0].Rows[0][3]
$datastore4 = $DataSet.Tables[0].Rows[0][4]
$datastore5 = $DataSet.Tables[0].Rows[0][5]
$datastore6 = $DataSet.Tables[0].Rows[0][6]
$datastore7 = $DataSet.Tables[0].Rows[0][7]
$script:ServerStatus1 = "DataBase Name:"+ $datastore+",Mirror State Number"+$datastore1+",Mirror State"+$datastore2+",Partner Name"+$datastore3+",Mirror Role"+$datastore4+",Safety Level"+$datastore5+",Witness"+$datastore6+",Timeout(In Sec)"+$datastore7
return $script:ServerStatus1
}
This is my function 2:
function getInsertServerStatus(
$svr1,
$inst2,
$ServerName = $svr1+"\"+$inst2,
$RemActonToBeTaken = 0,
$ServerStatus
) {
mirroring
$Script:ServerStatus1
$Script:ServerStatus= $ServerStatus1
Write-Host "ServerName=$ServerName"
Write-Host "InstanceName=$inst2"
Write-Host "ServerStatus=$ServerStatus1"
Write-Host "RemActonToBeTaken=$RemActonToBeTaken"
$SqlConnection1 = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection1.ConnectionString = "Server=$svr1\$inst2;Database=master;Integrated Security=True;"
$SqlConnection1.Open()
$SqlCmd1 = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd1.CommandText = "USP_RemedialActionDetails"
$SqlCmd1.Connection = $SqlConnection1
$SqlCmd1.CommandType = [System.Data.CommandType]::StoredProcedure
$InParameter1 = New-Object System.Data.SqlClient.SqlParameter;
$InParameter1 = $SqlCmd1.Parameters.Add("#ServerName" , [System.Data.SqlDbType]::String)
$InParameter1.Value = $ServerName
$InParameter1.Direction = [System.Data.ParameterDirection]"Input";
$InParameter2 = New-Object System.Data.SqlClient.SqlParameter;
$InParameter2=$SqlCmd1.Parameters.Add("#InstanceName" , [System.Data.SqlDbType]::String)
$InParameter2.Value = $inst2
$InParameter2.Direction = [System.Data.ParameterDirection]"Input";
$InParameter3 = New-Object System.Data.SqlClient.SqlParameter;
$InParameter3=$SqlCmd1.Parameters.Add("#ServerStatus" , [System.Data.SqlDbType]::String)
$InParameter3.Value = $ServerStatus1
$InParameter3.Direction = [System.Data.ParameterDirection]"Input";
$InParameter4 = New-Object System.Data.SqlClient.SqlParameter;
$InParameter4=$SqlCmd1.Parameters.Add("#RemActionToBeTaken" , [System.Data.SqlDbType]::String)
$InParameter4.Value = $RemActonToBeTaken
$InParameter4.Direction = [System.Data.ParameterDirection]"Input";
$result = $SqlCmd1.ExecuteNonQuery()
Write "result=$result"
$SqlConnection1.Close()
$SQLCmd1.Dispose() | Out-Null
}
I am calling function mirroring inside into function getInsertServerStatus.
Connection string into the function (mirroring) connection error because not found $server and $instance name.
There is some bugs in your code:
first, inside the function getInsertServerStatusyou you call mirroring without passing the parameters $svr $inst ....
it should be:
mirroring $svr1 $inst1 ... other parameters
second, Inside the function **mirroring** you call **GetConnectionString**
without passing parameters $servers $instance
it should be:
GetConnectionString $svr $inst
In the main program you call GetConnectionString $servers $instance and you don't pass the return value to a variable and has no effect in your code, remove this line
Modify your code with the suggested code.

Display custom message while installation using powershell

i am unable to figure out the mistake that i am doing.The following script will call a bunch of batch files and while the batch files are doing there job, the progress will be shown in a progress bar along with the name of the script. What i want to achieve is to display a custom message during the installation process. I am not able to find out the mistake, any help is deeply appreciated.
[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("System.Drawing") | Out-Null
Set-Location $PSScriptRoot
#Call scripts for installation
$ScriptsHome = Get-Item '.\test\forPS\*'
#Define Form
# Init Form
$Form = New-Object System.Windows.Forms.Form
$Form.width = 1000
$Form.height = 200
$Form.Text = "** Installation in Progress-PLEASE DO NOT CLOSE THIS WINDOW**"
$Form.Font = New-Object System.Drawing.Font("Times New Roman" ,12, [System.Drawing.FontStyle]::Regular)
$Form.MinimizeBox = $False
$Form.MaximizeBox = $False
$Form.WindowState = "Normal"
$Form.StartPosition = "CenterScreen"
$Form.Opacity = .8
$Form.BackColor = "Gray"
#Define ICON for Form
$Icon = New-Object System.Drawing.Graphics (".\ICON.jpg")
$Form.Icon = $Icon
# Init ProgressBar
$ProgressBar = New-Object System.Windows.Forms.ProgressBar
$ProgressBar.Maximum = $ScriptsHome.Count
$ProgressBar.Minimum = 0
$ProgressBar.Location = new-object System.Drawing.Size(10,70)
$ProgressBar.size = new-object System.Drawing.Size(967,10)
$Form.Controls.Add($ProgressBar)
$Form.Controls.Add($Messages)
#Running Script Name
$Label = New-Object System.Windows.Forms.Label
$Label.AutoSize = $true
$Label.Location = New-Object System.Drawing.Point(10,50)
$Form.Controls.Add($Label)
#Define Array messages
#Array
$Messages = #("Preparing to install patch set..Preparing to stop all related processes",
"Upgrading the application",
"Copying the missing folder",
"Applying the patch",
"Starting all previously stopped Services",
"Checkcing healthyness of the system after the installation this is may take up to half an hour...",
"Rebooting Server"
)
$Messages = New-Object System.Windows.Forms.Label
$Messages.AutoSize = $true
$Messages.Location = New-Object System.Drawing.Point(10,50)
$Form.Controls.Add($Messages)
# Add_Shown action
$ShownFormAction = {
$Form.Activate()
foreach ($script in $ScriptsHome) {
$ProgressBar.Increment(1)
#$Messages.Text = $Messages[$Messages]
$Label.Text = "$($script.Name)"
Start-Process $script.FullName -Wait -WindowStyle Hidden
}
$Form.Dispose()
}
$Form.Add_Shown($ShownFormAction)
# Show Form
$Form.ShowDialog()
Thanks in advance.
You're reusing the same variable name for the list of messages and the label showing the message itself:
$Messages = #("Preparing to install patch set..Preparing to stop all related processes",
"Upgrading the application",
"Copying the missing folder",
"Applying the patch",
"Starting all previously stopped Services",
"Checkcing healthyness of the system after the installation this is may take up to half an hour...",
"Rebooting Server"
)
$Messages = New-Object System.Windows.Forms.Label
$Messages.AutoSize = $true
$Messages.Location = New-Object System.Drawing.Point(10,50)
Rename one of them (ie. use $MessageLabel for the label):
$MessageLabel = New-Object System.Windows.Forms.Label
$MessageLabel.AutoSize = $true
$MessageLabel.Location = New-Object System.Drawing.Point(10,50)
Since you increment the ProgressBar by 1 every step, you can reuse the progress bar value to index into the $Messages array:
foreach ($script in $ScriptsHome) {
$ProgressBar.Increment(1)
$MessageLabel.Text = $Messages[$ProgressBar.Value - 1]
$Label.Text = "$($script.Name)"
Start-Process $script.FullName -Wait -WindowStyle Hidden
}

Import multisheet excel into sql server and export back to a multisheet excel

I have a multi sheet excel workbook with an unknown number of columns in each sheet. I am looping through each sheet and importing the data into a table in sql server. I then am running a query against that table to pull in a few more fields. I then want the result of that query to be exported into a multi sheet excel workbook. I am struggling with how to export this into a multi sheet workbook. In the code below I have it exporting to a csv, but I'm not sure that is the best way to do it. My plan was to then loop through the csvs to create the xlsx, but I could see that causing problems unless I separate everything into their own directories as this will run many times.
Param(
[String]$excelPath,
[String]$serverName,
[String]$databaseName,
[String]$tableName,
[String]$csvPath
)
$ErrorActionPreference = 'Stop'
[System.Reflection.Assembly]::LoadWithPartialName('Microsoft.SqlServer.SMO') | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName('Microsoft.SqlServer.SMO.SqlDataType') | Out-Null
Trap {
$err = $_.Exception
while ( $err.InnerException )
{
$err = $err.InnerException
Write-Output $err.Message
};
exit 1
}
if (test-path $excelTMGPath ) { rm $excelTMGPath } #delete the file if it already exists
$excel = New-Object -ComObject excel.application
$excel.visible = $False
$excel.displayalerts=$False
$workbook = $excel.Workbooks.Open($ExcelPath)
foreach ($ws in $workbook.Worksheets)
{
$workSheet = $ws.Name
Write-Output "Working on worksheet $workSheet"
$query = "select * from [$workSheet`$]";
$connectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=`"$excelPath`";Extended Properties=`"Excel 12.0 Xml;HDR=YES;IMEX=1`";"
# Instantiate some objects which will be needed
$serverSMO = New-Object Microsoft.SqlServer.Management.Smo.Server($serverName)
$db = $serverSMO.Databases[$databaseName];
$newTable = New-Object Microsoft.SqlServer.Management.Smo.Table ;
$newTable.Parent = $db;
$newTable.Name = $tableName ;
$conn = New-Object System.Data.OleDb.OleDbConnection($connectionString)
$conn.open()
$cmd = New-Object System.Data.OleDb.OleDbCommand($query,$conn)
$dataAdapter = New-Object System.Data.OleDb.OleDbDataAdapter($cmd)
$dataTable = New-Object System.Data.DataTable
$dataAdapter.fill($dataTable)
$conn.close()
# Drop the table if it exists
if($db.Tables.Contains($tableName).Equals($true))
{
($db.Tables[$tableName]).Drop()
}
# Iterate the columns in the DataTable object and add dynamically named columns to the SqlServer Table object.
foreach($col in $dataTable.Columns)
{
$sqlDataType = [Microsoft.SqlServer.Management.Smo.SqlDataType]::Varchar
$dataType = New-Object Microsoft.SqlServer.Management.Smo.DataType($sqlDataType);
$dataType.MaximumLength = 1000;
$newColumn = New-Object Microsoft.SqlServer.Management.Smo.Column($newTable,$col.ColumnName,$dataType);
$newColumn.DataType = $dataType;
$newTable.Columns.Add($newColumn);
}
$newTable.Create();
#bcp data into new table
$connectionString = "Data Source=$serverName;Integrated Security=true;Initial Catalog=$databaseName;"
$bc = New-Object ("Data.SqlClient.SqlBulkCopy") $connectionString
$bc.DestinationTableName = "$tableName"
$bc.WriteToServer($dataTable)
#Make sure column 3 is named MasterAccountKey for joining purposes
$sqlColumnRename =
#"
USE $databaseName
declare #MasterAccountKey varchar(255), #cmd varchar(500)
set #MasterAccountKey = (select COLUMN_NAME from INFORMATION_SCHEMA.columns
where table_name = 'zzzExcelSheet'
and ordinal_position = 3);
set #cmd = ('sp_RENAME ''zzzExcelSheet.' + #MasterAccountKey + ''', ''MasterAccountKey'', ''COLUMN''')
exec (#cmd)
"#
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "Data Source=$serverName;Initial Catalog=$databaseName;Integrated Security = True"
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.CommandText = $sqlColumnRename
$SqlCmd.Connection = $SqlConnection
$SqlConnection.Open()
$sqlCmd.ExecuteNonQuery()
$SqlConnection.Close()
# Connect to SQL and query data, extract data to SQL Adapter
$SqlQuery = #"
select t.*,
b.Social_Security_Number as SSN,
b.PRIMARY_NAME,
b.ADDR_LINE_1,
b.ADDR_LINE_2,
b.CITY,
b.STATE,
b.ZIP_CODE,
from
other tables b
"#
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "Data Source=$serverName;Initial Catalog=$databaseName;Integrated Security = True"
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.CommandText = $SqlQuery
$SqlCmd.Connection = $SqlConnection
$SqlAdapter = New-Object System.Data.SqlClient.SqlDataAdapter
Try{
$SqlAdapter.SelectCommand = $SqlCmd
}
Catch
{
exit 1
}
$DataSet = New-Object System.Data.DataSet
$nRecs = $SqlAdapter.Fill($DataSet)
$nRecs | Out-Null
#Populate Hash Table
$objTable = $DataSet.Tables[0]
#Export Hash Table to CSV File
$objTable | Export-CSV $objTable | Export-CSV $csvPath -noType
if (test-path $csvPath ) { rm $csvPath }
}
$ws = $null
$workSheet = $null
$workbook.Close()
$workbook = $null
$excel.quit()
while ([System.Runtime.InteropServices.Marshal]::FinalReleaseComObject($excel)) {}
$excel = $null

Resources