Issue with Powershell SMO SQL Server restore - sql-server

I am running into an issue with doing a Powershell SQL restore. I have this code
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SMO") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SmoExtended") | Out-Null
[Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.ConnectionInfo") | Out-Null
[Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SmoEnum") | Out-Null
$backupFile = 'C:\Temp\User_20191029152532.bak'
$server = New-Object ("Microsoft.SqlServer.Management.Smo.Server") "(local)"
$backupDevice = New-Object("Microsoft.SqlServer.Management.Smo.BackupDeviceItem") ($backupFile, "File")
$smoRestore = new-object("Microsoft.SqlServer.Management.Smo.Restore")
$smoRestore.NoRecovery = $false;
$smoRestore.ReplaceDatabase = $true;
$smoRestore.Action = "Database"
$smoRestorePercentCompleteNotification = 10;
$smoRestore.Devices.Add($backupDevice)
$smoRestoreDetails = $smoRestore.ReadBackupHeader($server)
"Database Name from Backup Header : " +$smoRestoreDetails.Rows[0]["DatabaseName"]
$smoRestore.Database =$smoRestoreDetails.Rows[0]["DatabaseName"]
$smoRestoreFile = New-Object("Microsoft.SqlServer.Management.Smo.RelocateFile")
$smoRestoreLog = New-Object("Microsoft.SqlServer.Management.Smo.RelocateFile")
$smoRestoreFile.LogicalFileName = $smoRestoreDetails.Rows[0]["DatabaseName"]
$smoRestoreFile.PhysicalFileName = $server.Information.MasterDBPath + "\" + $smoRestore.Database + "_Data.mdf"
$smoRestoreLog.LogicalFileName = $smoRestoreDetails.Rows[0]["DatabaseName"] + "_Log"
$smoRestoreLog.PhysicalFileName = $server.Information.MasterDBLogPath + "\" + $smoRestore.Database + "_Log.ldf"
$smoRestore.RelocateFiles.Add($smoRestoreFile)
$smoRestore.RelocateFiles.Add($smoRestoreLog)
$smoRestore.SqlRestore($server)
Everything works fine if I run this. However, I would like to provide a variable for which backup to restore. So I changed the top part of the code to this:
$path = 'C:\Temp'
$db_name = 'User'
$file = Get-ChildItem $path '*.bak' | Select-Object basename | Where-Object {$_.basename -like $db_name + '*' }
$backupFile = $path + '\' + $file
When I make this change, I start getting the below error.
Exception calling "ReadBackupHeader" with "1" argument(s): "An exception occurred while executing a Transact-SQL statement or batch."
At line:23 char:1
+ $smoRestoreDetails = $smoRestore.ReadBackupHeader($server)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : ExecutionFailureException
Not really sure why it will not accept the $file variable that I am passing. If I look at the variable, it is returning the right value.

Stupid issue on my part. $file did not include the extension. Adding the .bak to $file fixed the issue.

Related

How do you script out SQL Server agent jobs to single or individual files

I've tried various Powershell scripts but they fail with:
The following exception occurred while trying to enumerate the collection: "An exception occurred while executing a Transact-SQL statement or batch.".
At H:\Create_SQLAgentJobSripts2.ps1:89 char:22
foreach ($job in $s.JobServer.Jobs)
~~~~~~~~~~~~~~~~~
CategoryInfo : NotSpecified: (:) [], ExtendedTypeSystemException
FullyQualifiedErrorId : ExceptionInGetEnumerator
What has gone wrong or how can I get better debugging on this error?
I executed this script:
.\Create_SQLAgentJobSripts2.ps1 .\ServerNameList.txt
Here's the script
param([String]$ServerListPath)
#write-host "Parameter: $ServerListPath"
#Load the input file into an Object array
$ServerNameList = get-content -path $ServerListPath
#Load the SQL Server SMO Assemly
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo") | Out-Null
#Create a new SqlConnection object
$objSQLConnection = New-Object System.Data.SqlClient.SqlConnection
#For each server in the array do the following.
foreach($ServerName in $ServerNameList)
{
Write-Host "Beginning with Server: $ServerName"
Try
{
$objSQLConnection.ConnectionString = "Server=$ServerName;Initial Catalog=CED_NCT_RESOURCE_TRACK;Persist Security Info=True;User ID=CEDNCTAdmin;Password=CEDNCTAdmin;"
Write-Host "Trying to connect to SQL Server instance on $ServerName..." -NoNewline
$objSQLConnection.Open() | Out-Null
Write-Host "Success."
$objSQLConnection.Close()
}
Catch
{
Write-Host -BackgroundColor Red -ForegroundColor White "Fail"
$errText = $Error[0].ToString()
if ($errText.Contains("network-related"))
{Write-Host "Connection Error. Check server name, port, firewall."}
Write-Host $errText
continue
}
# Won't be using this object again
Remove-Variable -Name objSQLConnection
#If the output folder does not exist then create it
$OutputFolder = ".\$ServerName"
if (!(Test-Path $OutputFolder))
{
write-host ("Creating directory: " + $OutputFolder)
New-Item -ItemType directory -Path $OutputFolder
}
else
{
write-host ("Directory already exists: " + $OutputFolder)
}
write-host "File: $(".\$OutputFolder\" + $($_.Name -replace '\\', '') + ".job.sql")"
# Connect to the instance using SMO
$s = new-object ('Microsoft.SqlServer.Management.Smo.Server') $ServerName
write-host ("SQL Server Edition: " + $s.Edition)
write-host ("SQL Agent ErrorLogFile: " + $s.JobServer.ErrorLogFile)
# Instantiate the Scripter object and set the base properties
$scrp = new-object ('Microsoft.SqlServer.Management.Smo.Scripter') ($ServerName)
write-host ("SCRP ToString():" + $scrp.ToString())
write-host ("Test scrp - Server: " + $scrp.Server)
#The next step is to set the properties for the script files:
$scrp.Options.ScriptDrops = $False
$scrp.Options.WithDependencies = $False
$scrp.Options.IncludeHeaders = $True
$scrp.Options.AppendToFile = $False
$scrp.Options.ToFileOnly = $True
$scrp.Options.ClusteredIndexes = $True
$scrp.Options.DriAll = $True
$scrp.Options.Indexes = $False
$scrp.Options.Triggers = $False
$scrp.Options.IncludeIfNotExists = $True
#Now, we can cycle through the jobs and create scripts for each job on the server.
# Create the script file for each job
foreach ($job in $s.JobServer.Jobs)
{
$jobname = $job.Name
write-host ("Job: " + $jobname)
$jobfilename = ($OutputFolder + "\" + $jobname + ".job.sql")
$scrp.Options.FileName = $jobfilename
write-host "Filename: $jobfilename"
#This line blows up
$scrp.Script($job)
}
}
Possibly you're not instantiating the Server object correctly. Try the following instead...
# Alternative 1: With servername and port, using Trusted Connection...
$ServerName = 'YourServerName,1433'
$ServerConnection = New-Object Microsoft.SqlServer.Management.Common.ServerConnection -ArgumentList #( $ServerName )
# Alternative 2: With an SqlConnection object
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "Server=$ServerName;Initial Catalog=CED_NCT_RESOURCE_TRACK;Persist Security Info=True;User ID=CEDNCTAdmin;Password=CEDNCTAdmin;"
$SqlConnection.Open() | Out-Null
$ServerConnection = New-Object Microsoft.SqlServer.Management.Common.ServerConnection -ArgumentList #( $SqlConnection )
# Then...
$Server = New-Object Microsoft.SqlServer.Management.Smo.Server -ArgumentList #( $ServerConnection )
$Server.JobServer.Jobs | ForEach-Object {
Write-Host "Job: $($_.Name)"
}

Powershell SQL Server stored procedure backup

I am trying to backup one particular stored procedure from a SQL Server database by passing parameters from a Python program. Here is the code that I have tried but I keep getting an error.
param([string]$server='dbsed0898', [string]$dbname='global_hub',[string]$sp='dbo.gs_eligibility')
[System.Reflection.Assembly]::LoadWithPartialName(“Microsoft.SqlServer.SMO”) | out-null
$SMOserver = 'Microsoft.SqlServer.Management.Smo' #-argumentlist $server
$srv = New-Object("$SMOserver.Server") $server
$db = $srv.databases[$dbname]
$Objects = $db.storedprocedures[$sp]
$scripter = new-object ("$SMOserver.Scripter") $srv
$Scripter.Script($Objects) | Out-File
" C:\Users\fthoma15\Documents\backup_03212020.sql"
$db = $SMOserver.databases[$dbname]
$Objects = $db.storedprocedures[$sp]
$Scripter.Script($Objects) | Out-File
"C:\Users\fthoma15\Documents\backup_03212020.sql"
Error:
Multiple ambiguous overloads found for "Script" and the argument count: "1".
At line:12 char:5
+ $Scripter.Script($Objects) | Out-File "C:\Users\fthoma15\Document ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodException
+ FullyQualifiedErrorId : MethodCountCouldNotFindBest
Can someone help me?
Here is what i did.
param([string]$server='test', [string]$dbname='test',[string[]]$sp=('test','test'))
[System.Reflection.Assembly]::LoadWithPartialName(“Microsoft.SqlServer.SMO”) | out-
null
$SMOserver = new-object ("Microsoft.SqlServer.Management.Smo.Scripter") #-argumentlist
$server
$srv = new-Object Microsoft.SqlServer.Management.Smo.Server("$server")
$db = New-Object Microsoft.SqlServer.Management.Smo.Database
$db = $srv.Databases.Item("$dbname")
$Objects = $db.storedprocedures[$sp[1,3]]
$scripter = new-object ("$SMOserver") $srv
$Scripter.Script($Objects) | Out-File
"C:\Users\fthoma15\Documents\backup_03212020.sql"
As suggested by AlwaysLearning, i changed the sp variable to an array list,splitting both schema and sp name.

Powershell Script Issue with SQL Server 2012/2014

I have a PowerShell script which works well when I run it on server with SQL Server default instance (MSSQLSERVER) but the same script fails on a server with a named instance (MSSQL$instance)
For the default instance (MSSQLSERVER)
[Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo")
$service = Get-service -name 'MSSQLSERVER'
$status = $service.status
$CreateDB = "db-Test"
if ( $status -eq "Running" )
{
'Success' | Out-File -FilePath c:\sqltest.log -Encoding ASCII
$srv = new-Object Microsoft.SqlServer.Management.Smo.Server("(local)")
$db = New-Object Microsoft.SqlServer.Management.Smo.Database($srv, "$CreateDB")
$db.Create()
$db.CreateDate
}
else
{
'Failed' | Out-File -FilePath c:\sqltest.log -Encoding ASCII
}
Above script works very well. But below script throws error :
For named instance :
[Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo")
$service = Get-service -name 'MSSQL$instancename'
$status = $service.status
$CreateDB = "db-Test"
if ( $status -eq "Running" )
{
'Success' | Out-File -FilePath c:\sqltest.log -Encoding ASCII
$srv = new-Object Microsoft.SqlServer.Management.Smo.Server("(local)")
$db = New-Object Microsoft.SqlServer.Management.Smo.Database($srv, "$CreateDB")
$db.Create()
$db.CreateDate
}
else
{
'Failed' | Out-File -FilePath c:\sqltest.log -Encoding ASCII
}
Above script for named SQL instance throws below error :
New-Object : Exception calling ".ctor" with "2" argument(s): "SetParent failed for Database 'Netmagic-Test'. "
At C:\mssql-test.ps1:11 char:7
+ $db = New-Object Microsoft.SqlServer.Management.Smo.Database($srv, "$CreateDB")
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [New-Object], MethodInvocationException
+ FullyQualifiedErrorId : ConstructorInvokedThrowException,Microsoft.PowerShell.Commands.NewObjectCommand
You cannot call a method on a null-valued expression.
At C:\mssql-test.ps1:12 char:1
+ $db.Create()
+ ~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
Error Screen
Thanks,
Viral

Powershell error: “Cannot convert value of type ”Microsoft.SqlServer.Management.Smo.Server“ to type…

The answer provided for this question is unacceptable.
Error I'm getting from Powershell:
Cannot convert argument "srv", with value: "[DBADEV\SQL2008r2]", for "SqlBackup" to type "Microsoft.SqlServer.Management.Smo.Server": "Cannot convert the "[DBADEV\SQL2008r2]" value of type
"Microsoft.SqlServer.Management.Smo.Server" to type "Microsoft.SqlServer.Management.Smo.Server"."
At line:23 char:1
+ $backup.SqlBackup($srv)
+ ~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : MethodArgumentConversionInvalidCastArgument
I'm attempting to write a PowerShell script to restore a database from our Production box and into our DBADEV box. Below is the code I'm using which is then producing the error.
#Clear Screen
cls
#load assemblies
[System.Reflection.Assembly]::LoadWithPartialName('Microsoft.SqlServer.SMO') | out-null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SmoExtended") | Out-Null
$ErrorActionPreference = "Inquire"
# Restore [SQLSRV2k8-0102\SQL2008] instance
$BackupFile = Get-ChildItem "\\NetworkShare\r`$\MSSQL10.SQL2008\MSSQL\Backup\AdventureWorks2008r2" | select -Last 1
$BackupFile
$srv = New-Object Microsoft.SqlServer.Management.Smo.Server("DBADEV\SQL2008r2")
$res = New-Object Microsoft.SqlServer.Management.Smo.Restore
$backup = New-Object Microsoft.SqlServer.Management.Smo.Backup
$Backup.Devices.AddDevice($BackupFile, [Microsoft.SqlServer.Management.Smo.DeviceType]::File)
$Backup.Database = "AdventureWorks2008r2"
$Backup.Action = [Microsoft.SqlServer.Management.Smo.BackupActionType]::Database
$backup.Initialize = $true
$backup.SqlBackup($srv)
$srv.Databases["AdventureWorks2008r2"].Drop()
$res.Devices.AddDevice($BackupFile, [Microsoft.SqlServer.Management.Smo.DeviceType]::File)
$res.Database = "AdventureWorks2008r2"
$res.NoRecovery = $true
$res.SqlRestore($srv)
The error seems a bit cryptic to me (as do most PowerShell errors). Any thoughts on why this is occurring? I'm also getting the error when I use Mike Fal's powershell script here: http://www.mikefal.net/2014/07/22/restoreautomation-powershell-module/

Folder permissions through powershell

im trying to set some rights on a newly created user in AD.
After I have created the folder, I try to set the various rights like this:
$Rights = [System.Security.AccessControl.FileSystemRights]::FullControl
$Inherit = #([System.Security.AccessControl.InheritanceFlags]::ContainerInherit,[System.Security.AccessControl.InheritanceFlags]::ObjectInherit)
$Propagation = [System.Security.AccessControl.PropagationFlags]::None
$Access =[System.Security.AccessControl.AccessControlType]::Allow
$ACL = New-Object System.Security.Principal.NTAccount "localdomain\$userprincipalname"
$objACE = New-Object System.Security.AccessControl.FileSystemAccessRule($ACL, $Rights, $Inherit, $Propagation, $Access)
$ACL = Get-Acl -Path $userDir
$ACL.AddAccessRule($objACE)
Set-ACL -Path $userDir -AclObject $ACL
The error I get is related to the parameters i pass to AddAccessRule
Exception calling "AddAccessRule" with "1" argument(s): "Some or all identity references could not be translated."
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException
But I cannot see any error here, so I would really appreciate another set of eyes.
Ok so my solution works, and as far as I can find, is the way to set rights on a folder.
$Rights = [System.Security.AccessControl.FileSystemRights]::FullControl
$Inherit = #([System.Security.AccessControl.InheritanceFlags]::ContainerInherit,[System.Security.AccessControl.InheritanceFlags]::ObjectInherit)
$Propagation = [System.Security.AccessControl.PropagationFlags]::None
$Access =[System.Security.AccessControl.AccessControlType]::Allow
$ACL = New-Object System.Security.Principal.NTAccount "localdomain\$userprincipalname"
$objACE = New-Object System.Security.AccessControl.FileSystemAccessRule($ACL, $Rights,$Inherit, $Propagation, $Access)
$ACL = Get-Acl -Path $userDir
$ACL.AddAccessRule($objACE)
Set-ACL -Path $userDir -AclObject $ACL

Resources