Change MSSQL Schema Ownership via Powershell - sql-server

I'm trying to change the "schemas owned by this user" on a database using the following powershell script:
$dbname = "mydb"
$sql_server = "mysqlserver"
$username = "myuser"
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SMO") | Out-Null
$server = New-Object ("Microsoft.SqlServer.Management.Smo.Server")($sql_server)
$db = $server.Databases["$dbname"]
$login = $server.Logins[$username]
$roleName = "db_owner"
if(-not $db.Users.Contains($login.Name)){
$user = New-Object('Microsoft.SqlServer.Management.Smo.User') $db, $login.Name
$user.Login = $login.Name
$user.create();
}
$user = $db.Users[$login.Name]
$role = $db.Roles[$roleName]
$role.AddMember($user.Name);
$schema = $db.Schemas["dbo"]
$schema.Owner = "myuser"
$schema.Alter()
When I get to the step $schema.Alter() I get the following error:
Exception calling "Alter" with "0" argument(s): "Alter failed for Schema 'dbo'. "
At line:1 char:1
+ $schema.Alter()
+ ~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : FailedOperationException
I get the impression the Alter Method is looking for more parameters but I'm not sure what parameters it wants. Anyone have any suggestions what I'm doing wrong?
Thanks
Brad

In my experience, the top level exception is not helpful. My typical method for dealing with this is something like $e = $error[0]; and then calling $e.Exception, $e.Exception.InnerException, $e.Exception.InnerException.InnerException, … until I get to the actual error. This doesn't solve your problem, but at least can give you a better idea of what the problem is.

Related

PowerShell Exception calling "Open" with "0" argument(s): "ORA-12537: Network Session: End of file"

I am getting this error in
PowerShell
I am trying to stablish a connection to an Oracle Database and see if I can get any data in return. I found some code and put this together. I see most people use the "connection.open() to stablish a connection to the database so that is the norm but I am not sure why I am getting this errors any ideas?
PS SQLSERVER:\>
Exception calling "Open" with "0" argument(s): "ORA-12537: Network Session: End of file"
At line:8 char:1
+ $connection.open()
+ ~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : OracleException
Exception calling "ExecuteReader" with "0" argument(s): "Connection must be open for this operation"
..
..
..
PS SQLSERVER:\>
here is my code
Add-Type -Path "C:\Oracle\product\12.2.0\client_1\ODP.NET\managed\common\Oracle.ManagedDataAccess.dll"
$username = Read-Host -Prompt "Enter database username"
$password = Read-Host -Prompt "Enter database password"
$datasource = Read-Host -Prompt "Enter database TNS name"
$query = "SELECT SYSDATE FROM DUAL"
$connectionString = 'User Id=' + $username + ';Password=' + $password + ';Data Source=' + $datasource
$connection = New-Object Oracle.ManagedDataAccess.Client.OracleConnection($connectionString)
$connection.open()
$command=$connection.CreateCommand()
$command.CommandText=$query
$reader=$command.ExecuteReader()
while ($reader.Read()) {
$reader.GetString(1) + ', ' + $reader.GetString(0)
}
$connection.Close()
Try to use System.Data.OracleClient instead of Oracle.ManagedDataAccess.dll. You have to have the Oracle Client installed on the machine you are executing the script.

Invoke-Sqlcmd error in Loop, No error once?

If I run this .ps1 script-
$secID = Invoke-Sqlcmd -ServerInstance "MyDBServer" -Database "MyDataBase"-Query "SELECT SysID FROM dbo.SecurityLevels WHERE LEVELNAME LIKE '%User%';"
Write-Host "MyDataBase"
Write-Host $secID.SysID
I get the following on the console with no error -
MyDataBase
18
However if I try this same query in a for loop in a larger script -
$dbservers = #('DataBaseServer1', 'DataBaseServer2')
foreach ($dbserver in $dbservers)
{
$databases = Get-SqlDatabase -ServerInstance $dbserver | Where-Object { $_.Name -Match '\d{3,4}' -and $_.Name -notlike '*test*'}
foreach ($database in $databases)
{
$secID = Invoke-Sqlcmd -ServerInstance $dbserver.Name -Database $database.Name -Query "SELECT SysID FROM dbo.SecurityLevels WHERE LEVELNAME LIKE '%User%';"
Write-Host $database.Name
Write-Host $secID.SysID
}
}
I get the correct query result but errors preceding it on the console -
Invoke-Sqlcmd : A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that
the instance name is correct and that SQL Server is configured to allow remote connections. (provider: Named Pipes Provider, error: 40 - Could not open a connection to SQL Server)
At \SQL.ps1:28 char:13
+ ... $secID = Invoke-Sqlcmd -ConnectionString $ConnectionString -Query ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [Invoke-Sqlcmd], SqlException
+ FullyQualifiedErrorId : SqlExceptionError,Microsoft.SqlServer.Management.PowerShell.GetScriptCommand
Invoke-Sqlcmd :
At \SQL.ps1:28 char:13
+ ... $secID = Invoke-Sqlcmd -ConnectionString $ConnectionString -Query ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ParserError: (:) [Invoke-Sqlcmd], ParserException
+ FullyQualifiedErrorId : ExecutionFailureException,Microsoft.SqlServer.Management.PowerShell.GetScriptCommand*
MyDataBase
18
Why do I get errors when running it in the loop versus running it one time? Also why does the query work even though I get an error? I think I am missing something any help would be greatly appreciated!
I think its because you are calling property Name on a String, effectively returning nothing. try this (I just deleted the calling of the property $dbserver.Nameto $dbserver):
$dbservers = #('DataBaseServer1', 'DataBaseServer2')
foreach ($dbserver in $dbservers)
{
$databases = Get-SqlDatabase -ServerInstance $dbserver | Where-Object { $_.Name -Match '\d{3,4}' -and $_.Name -notlike '*test*'}
foreach ($database in $databases)
{
$secID = Invoke-Sqlcmd -ServerInstance $dbserver -Database $database.Name -Query "SELECT SysID FROM dbo.SecurityLevels WHERE LEVELNAME LIKE '%User%';"
Write-Host $database.Name
Write-Host $secID.SysID
}
}
The error must be because its looking for a DB instance "" and it doesn't find it, and the query might still go though because the the first server might not have an instance, or because those values were already loaded into the properties from before. But I'm just speculating, haven't really used this cmdlets.
PS: if you want to avoid calling empty properties add Set-StrictMode -Version 2 to your script, example:
PS > $text = "This is just a string"
PS > $text.AnyProperty
PS > Set-StrictMode -Version 2
PS > $text.AnyProperty
The property 'AnyProperty' cannot be found on this object. Verify that the property exists.
At line:1 char:1
+ $text.AnyProperty
+ ~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], PropertyNotFoundException
+ FullyQualifiedErrorId : PropertyNotFoundStrict
Hope it helps.

Exception calling ".ctor" with "2" argument(s): "SetParent failed for Database 'XXX' ."

I have a problem with running SQLPS commands to create a DB on Windows Server 2012R2 and Powershell v4
#Import SQL Server Module called SQLPS
Import-Module SQLPS -DisableNameChecking
#Your SQL Server Instance Name
$Inst = "sql03"
$Srvr = New-Object -TypeName Microsoft.SqlServer.Management.Smo.Server -ArgumentList $Inst
#database PSDB with default settings
#by assuming that this database does not yet exist in current instance
$DBName = "PSDB"
$db = New-Object -TypeName Microsoft.SqlServer.Management.Smo.Database($Srvr, $DBName)
$db.Create()
#Confirm, list databases in your current instance
$Srvr.Databases |
Select Name, Status, Owner, CreateDate
I receive the below error:
New-Object : Exception calling ".ctor" with "2" argument(s): "SetParent failed for Database 'PSDB'. "
At C:\test.ps1:11 char:7
+ $db = New-Object -TypeName Microsoft.SqlServer.Management.Smo.Database($Srvr, $D ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [New-Object], MethodInvocationException
+ FullyQualifiedErrorId : ConstructorInvokedThrowException,Microsoft.PowerShell.Commands.NewObjectCommand
You cannot call a method on a null-valued expression.
At C:\test.ps1:12 char:1
+ $db.Create()
+ ~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
The following exception occurred while trying to enumerate the collection: "Failed to connect to server sql03.".
At C:\test.ps1:15 char:1
+ $Srvr.Databases |
+ ~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], ExtendedTypeSystemException
+ FullyQualifiedErrorId : ExceptionInGetEnumerator
Any suggestions how to fix this?
If you are working locally try replacing:
$Srvr = New-Object -TypeName Microsoft.SqlServer.Management.Smo.Server -ArgumentList $Inst
With:
$Srvr = new-object ('Microsoft.SqlServer.Management.Smo.Server') localhost

powershell set database IndexOutOfRangeException

I'm trying to set a database name in powershell using Microsoft.SqlServer.SMO. When I execute my script it runs in error with the following error text:
format-default : Index was outside the bounds of the array.
+ CategoryInfo : NotSpecified: (:) [format-default], IndexOutOfRangeException
+ FullyQualifiedErrorId : System.IndexOutOfRangeException,Microsoft.PowerShell.Commands.FormatDefaultCommand
The server is set as follows
$srv = New-Object "Microsoft.SqlServer.Management.SMO.Server" $server
$srv.ConnectionContext.LoginSecure=$false;
$srv.ConnectionContext.set_Login("login");
$srv.ConnectionContext.set_Password("password")
$srv.Databases | Select name,
shows me the proper databases, but when setting the database,
$db = $srv.Databases[$database]
the error is thrown.
This scrip does work in other sqlservers.
Any solutions for this issue?
It looks like the database "CRD_DEV" does not exist on the server where the script throws the error.
That or the user does not have access to that database.
The IndexOutOfRangeException is thrown because there is no item in $srv.Databases that matches "CRD_DEV"

How to get SQL Server Management Studio tab messages in PowerShell?

With Powershell, I execute a SQL script which returns a generated script in the tab "Messages" of SQL Server Management Studio. But I can't get it in PowerShell.
When I do this :
$ps = [PowerShell]::Create()
[ref]$e = New-Object System.Management.Automation.Runspaces.PSSnapInException
$ps.Runspace.RunspaceConfiguration.AddPSSnapIn( "SqlServerCmdletSnapin100", $e ) | Out-Null
$ps.AddCommand( "Invoke-Sqlcmd" ).AddParameter( "ServerInstance", "localhost").AddParameter( "Database", "MyDatabase").AddParameter("InputFile", "D:\MyScript.sql").AddParameter("Verbose")
$ps.Invoke()
$ps.Streams
$ps.Streams.Verbose | % { $_.Message | Out-File -Append D:\SqlLog.txt }
I get this error :
PS D:\NEMO\Scripts\Database> $ps.Invoke()
Exception calling "Invoke" with "0" argument(s): "Object reference not set to an instance of an object."
At line:1 char:11
+ $ps.Invoke <<<< ()
+ CategoryInfo : NotSpecified: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : DotNetMethodException
Thank you for your help.
So make Powershell to output messages is not that simple and it works only in command-line i think. Try this
write-host $line
Start-Transcript $outputfilepath
$ScriptParams = "DatabaseName=$line" "
Invoke-Sqlcmd -ServerInstance $SQLInstance -Username $SQLAdminUser -Password $SQLAdminPwd -InputFile "D:\File.sql" -verbose -Variable $ScriptParams
Stop-Transcript

Resources