DSCResources/ArcGIS_EGDB/ArcGIS_EGDB.MSSQL.psm1
function Invoke-CreateMSSQLSDEIfNotExist { [CmdletBinding()] param ( [System.String] [ValidateSet("SQLServerDatabase","AzureSQLDatabase","AzureMISQLDatabase")] $DatabaseType, [System.String] $DatabaseServer, [System.String] $DatabaseName, [PSCredential] $DatabaseServerAdministrator, [PSCredential] $SDECredential, [PSCredential] $DatabaseUser ) $IsSqlAzure = ($DatabaseType -ieq 'AzureSQLDatabase' -or $DatabaseType -ieq 'AzureMISQLDatabase') $SkipLoginExpiration= -not($IsSqlAzure) Write-Verbose "Testing connection to Database Server $($DatabaseServer)." Test-ConnectivityToSQLServer -Server $DatabaseServer -Credential $DatabaseServerAdministrator Write-Verbose "Connection to Database Server $($DatabaseServer) successful!" $SQLServerConnString = Get-DatabaseConnectionString -Server $DatabaseServer -Credential $DatabaseServerAdministrator ### ### Ensure Database exists ### if(-not(Test-SQLDatabaseExist $SQLServerConnString -DatabaseName $DatabaseName)) { if($DatabaseType -ieq 'AzureSQLDatabase'){ throw "AzureSQLDatabase Database creation type not supported. Please create the database as a pre-req." }else{ Write-Verbose "Creating Database '$DatabaseName' in Server '$DatabaseServer'" Invoke-CreateSQLDatabase -ConnString $SQLServerConnString -DatabaseName $DatabaseName } }else{ Write-Verbose "Database '$DatabaseName' in Server '$DatabaseServer' exists" } Write-Verbose "Enabling Database Privileges for GeoDatabase Administrator on Database '$DatabaseName'" Enable-DatabasePrivilegesForSQLGeoDatabaseAdministrator -ConnString $SQLServerConnString -DatabaseName $DatabaseName $SdeUserName = "sde" ### ### Create SDE User (if not exist) ### if(-not(Test-SQLLoginExist -ConnString $SQLServerConnString -UserName $SdeUserName)) { Write-Verbose "Creating Login for User '$SdeUserName' in Server '$DatabaseServer'" Invoke-SQLCreateLogin -ConnString $SQLServerConnString -Credential $SDECredential -SkipExpiration:$SkipLoginExpiration }else{ Write-Verbose "Login for User '$SdeUserName' exists in Server '$DatabaseServer'" } ### ### Ensure Sde Exists in the database. If not create one. ### $DbConnString = Get-DatabaseConnectionString -Server $DatabaseServer -Credential $DatabaseServerAdministrator -Database $DatabaseName if(-not(Test-SQLUserExist -ConnString $DbConnString -UserName $SdeUserName)){ Write-Verbose "Creating User '$SdeUserName' in Database '$DatabaseName'" Invoke-CreateSqlUser -ConnString $DbConnString -Credential $SDECredential -DefaultSchema '' # Create with no schema }else{ Write-Verbose "User '$SdeUserName' exists in Database '$DatabaseName'" } $DbConnStringForSdeUser = Get-DatabaseConnectionString -Server $DatabaseServer -Database $DatabaseName -Credential $SDECredential try { Test-SQLLogin -ConnString $DbConnStringForSdeUser Write-Verbose "User account $SdeUserName is a valid login" }catch { throw "Unable to login using Credentials provided for $SdeUserName." } ## ## Grant necessary privilages to Geodatabase Administrator 'sde' ## Grant-PrivilegesForSQLGeodatabaseAdministrator -ConnString $DbConnString -UserName $SdeUserName -GrantViewDatabaseState ## ## Ensure schema 'sde' exists in the database, # Needed Schema for ArcSDE ## $schema = $SdeUserName if(-not(Test-SQLSchemaExist -ConnString $DbConnStringForSdeUser -SchemaName $schema)){ Write-Verbose "Creating Schema '$schema' in Database '$DatabaseName'" Invoke-CreateSQLSchema -ConnString $DbConnString -SchemaName $schema Write-Verbose "Making user '$SdeUserName' owner of schema '$schema' in Database '$DatabaseName'" Invoke-AssignSchemaPrivilegesForSqlUser -ConnString $DbConnString -UserName $SdeUserName -DatabaseName $DatabaseName ` -Schema $schema -DbAdminUsername $DatabaseServerAdministrator.UserName }else{ Write-Verbose "Schema '$schema' exists in Database '$DatabaseName'" } $DatabaseUserName = $DatabaseUser.UserName ### ### Ensure Login for the user exists ### if(-not(Test-SQLLoginExist -ConnString $SQLServerConnString -UserName $DatabaseUserName)) { Write-Verbose "Creating Login for User '$DatabaseUserName' in Server '$DatabaseServer'" Invoke-SQLCreateLogin -ConnString $SQLServerConnString -Credential $DatabaseUser -SkipExpiration:$SkipLoginExpiration }else{ Write-Verbose "Login for User '$DatabaseUserName' exists in Server '$DatabaseServer'" } ### ### Ensure Database User Exists in the database. If not create one. ### if(-not(Test-SQLUserExist -ConnString $DbConnString -UserName $DatabaseUserName)){ Write-Verbose "Creating User '$DatabaseUserName' in Database '$DatabaseName'" Invoke-CreateSqlUser -ConnString $DbConnString -Credential $DatabaseUser -DefaultSchema '' # Create with no schema }else{ Write-Verbose "User '$DatabaseUserName' exists in Database '$DatabaseName'" } $DbConnStringForDBUser = Get-DatabaseConnectionString -Server $DatabaseServer -Database $DatabaseName -Credential $DatabaseUser try { Test-SQLLogin -ConnString $DbConnStringForDBUser Write-Verbose "User account $DatabaseUserName is a valid login" }catch { throw "Unable to login using Credentials provided for $DatabaseUserName." } ## ## Ensure schema 'DatabaseUserName' exists in the database, # Needed Schema for ArcSDE ## $schema = $DatabaseUserName if(-not(Test-SQLSchemaExist -ConnString $DbConnStringForDBUser -SchemaName $schema)){ Write-Verbose "Creating Schema '$schema' in Database '$DatabaseName'" Invoke-CreateSQLSchema -ConnString $DbConnString -SchemaName $schema Write-Verbose "Assigning schema '$schema' to User '$DatabaseUserName' in Database '$DatabaseName'" Invoke-AssignSchemaPrivilegesForSqlUser -ConnString $DbConnString -DatabaseName $DatabaseName ` -UserName $DatabaseUserName -Schema $schema ` -DbAdminUsername $DatabaseServerAdministrator.UserName }else{ Write-Verbose "Schema '$schema' exists in Database '$DatabaseName'" } Write-Verbose "Ensuring necessary privileges for '$DatabaseUserName' in Database '$DatabaseName'" Grant-PrivilegesForSQLSdeUser -ConnString $DbConnString -UserName $DatabaseUserName -SchemaName 'sde' } function Test-SQLLoginExist { [CmdletBinding()] param ( [System.String] $ConnString, [System.String] $UserName ) $sql = "SELECT COUNT(name) from sys.sql_logins WHERE name = '$UserName'" $count = Invoke-ExecuteSqlScalar -ConnString $ConnString -sql $sql $count -gt 0 } function Test-ConnectivityToSQLServer { [CmdletBinding()] param( [System.String] $Server, [System.Management.Automation.PSCredential] $Credential ) $connStr = Get-DatabaseConnectionString -Server $Server -Credential $Credential try { Test-SQLDatabaseExist -ConnString $connStr -DatabaseName 'master' } catch{ throw "Unable to connect to Server '$Server' using UserID:- '$($Credential.UserName)'. Please verify that the server is reachable" } } function Test-SQLLogin { [CmdletBinding()] param ( [System.String] $ConnString ) $sql = 'SELECT COUNT(*) from sys.tables' Invoke-ExecuteSqlNonQuery -ConnString $ConnString -sql $sql } function Invoke-SQLCreateLogin { [CmdletBinding()] param ( [System.String] $ConnString, [System.Management.Automation.PSCredential] $Credential, [switch] $SkipExpiration ) $sql = "CREATE LOGIN [$($Credential.UserName)] WITH PASSWORD = '$($Credential.GetNetworkCredential().Password)'" if($SkipExpiration){ $sql += ' , CHECK_EXPIRATION=OFF, CHECK_POLICY=ON' } Invoke-ExecuteSqlNonQuery -ConnString $ConnString -sql $sql } function Invoke-SQLDeleteLogin { [CmdletBinding()] param ( [System.String] $ConnString, [System.String] $UserName ) $sql = "DROP LOGIN [$UserName]" Invoke-ExecuteSqlNonQuery -ConnString $ConnString -sql $sql } function Invoke-CreateSQLDatabase { [CmdletBinding()] param ( [System.String] $ConnString, [System.String] $DatabaseName ) $sql = "CREATE DATABASE [$DatabaseName]" Invoke-ExecuteSqlNonQuery -ConnString $ConnString -sql $sql } function Test-SQLDatabaseExist { [CmdletBinding()] param ( [System.String] $ConnString, [System.String] $DatabaseName ) $sql = "SELECT COUNT(name) from sys.sysdatabases WHERE name = '$DatabaseName'" $count = Invoke-ExecuteSqlScalar -ConnString $ConnString -sql $sql $count -gt 0 } function Test-SQLUserExist { [CmdletBinding()] param ( [System.String] $ConnString, [System.String] $UserName ) $sql = "SELECT COUNT(NAME) FROM SYS.DATABASE_PRINCIPALS WHERE Name = '$UserName'" $count = Invoke-ExecuteSqlScalar -ConnString $ConnString -sql $sql $count -gt 0 } function Invoke-CreateSqlUser { [CmdletBinding()] param ( [System.String] $ConnString, [System.Management.Automation.PSCredential] $Credential, [System.String] $DefaultSchema = $Credential.UserName ) $UserName = $Credential.UserName $sql = "CREATE USER [$UserName] FOR LOGIN [$UserName]" if($DefaultSchema -and $DefaultSchema.Length -gt 0){ $sql += " WITH DEFAULT_SCHEMA = [$DefaultSchema]" } Invoke-ExecuteSqlNonQuery -ConnString $ConnString -sql $sql if($DefaultSchema -and $DefaultSchema.Length -gt 0) { $sql = "GRANT CONTROL ON SCHEMA::[$DefaultSchema] TO [$UserName]" Invoke-ExecuteSqlNonQuery -ConnString $ConnString -sql $sql } } function Invoke-AssignSchemaPrivilegesForSqlUser { [CmdletBinding()] param ( [System.String] $ConnString, [System.String] $DbAdminUsername, [System.String] $DatabaseName, [System.String] $UserName, [System.String] $Schema ) $sql = "ALTER USER [$UserName] WITH DEFAULT_SCHEMA = [$Schema]" Invoke-ExecuteSqlNonQuery -ConnString $ConnString -sql $sql $sql = "GRANT CONTROL ON SCHEMA::[$Schema] TO [$UserName]" Invoke-ExecuteSqlNonQuery -ConnString $ConnString -sql $sql $sql = "ALTER AUTHORIZATION ON SCHEMA::[$Schema] TO [$UserName]" Invoke-ExecuteSqlNonQuery -ConnString $ConnString -sql $sql } function Invoke-DropSQLUser { [CmdletBinding()] param ( [System.String] $ConnString, [System.String] $UserName ) $sql = "DROP USER [$UserName]" Invoke-ExecuteSqlNonQuery -ConnString $ConnString -sql $sql } function Test-SQLSchemaExist { [CmdletBinding()] param ( [System.String] $ConnString, [System.String] $SchemaName ) $sql = "SELECT Count(Name) FROM sys.schemas WHERE name = '$SchemaName'" $count = Invoke-ExecuteSqlScalar -ConnString $ConnString -sql $sql $count -gt 0 } function Invoke-CreateSQLSchema { [CmdletBinding()] param ( [System.String] $ConnString, [System.String] $SchemaName, [System.String] $SchemaOwnerName ) if($SchemaOwnerName -and $SchemaOwnerName.Length -gt 0) { $sql = "CREATE SCHEMA [$SchemaName] AUTHORIZATION $SchemaOwnerName" } else { $sql = "CREATE SCHEMA [$SchemaName]" } Invoke-ExecuteSqlNonQuery -ConnString $ConnString -sql $sql } function Invoke-ChangeSQLDatabaseOwnership { [CmdletBinding()] param ( [System.String] $ConnString, [System.String] $UserName, [System.String] $DatabaseName ) $sql = "EXEC sp_changedbowner N'$UserName'" Invoke-ExecuteSqlNonQuery -ConnString $ConnString -sql $sql } function Enable-DatabasePrivilegesForSQLGeoDatabaseAdministrator { [CmdletBinding()] param ( [System.String] $ConnString, [System.String] $DatabaseName ) $sql = "ALTER DATABASE [$DatabaseName] SET READ_COMMITTED_SNAPSHOT ON WITH ROLLBACK IMMEDIATE" Invoke-ExecuteSqlNonQuery -ConnString $ConnString -sql $sql $sql = "ALTER DATABASE [$DatabaseName] SET ALLOW_SNAPSHOT_ISOLATION ON" Invoke-ExecuteSqlNonQuery -ConnString $ConnString -sql $sql } function Grant-PrivilegesForSQLGeodatabaseAdministrator { [CmdletBinding()] param ( [System.String] $ConnString, [System.String] $UserName, [switch] $GrantViewDatabaseState ) <# $sql = "SP_DROPUSER '$UserName'" Invoke-ExecuteSqlNonQuery -ConnString $ConnString -sql $sql $sql = "EXEC sp_changedbowner '$UserName'" Invoke-ExecuteSqlNonQuery -ConnString $ConnString -sql $sql #> Write-Verbose "Granting Permissions" $sql = "GRANT CREATE PROCEDURE TO [$UserName]" Invoke-ExecuteSqlNonQuery -ConnString $ConnString -sql $sql $sql = "GRANT CREATE FUNCTION TO [$UserName]" Invoke-ExecuteSqlNonQuery -ConnString $ConnString -sql $sql $sql = "GRANT CREATE TABLE TO [$UserName]" Invoke-ExecuteSqlNonQuery -ConnString $ConnString -sql $sql $sql = "GRANT CREATE VIEW TO [$UserName]" Invoke-ExecuteSqlNonQuery -ConnString $ConnString -sql $sql if($GrantViewDatabaseState) { $sql = "GRANT VIEW DATABASE STATE TO [$UserName]" Invoke-ExecuteSqlNonQuery -ConnString $ConnString -sql $sql } } function Grant-PrivilegesForSQLSdeUser { [CmdletBinding()] param ( [System.String] $ConnString, [System.String] $UserName, [System.String] $SchemaName = "sde" ) #$sql = "EXEC sp_addrolemember N'db_datareader', N'$UserName'" #Invoke-ExecuteSqlNonQuery -ConnString $ConnString -sql $sql #$sql = "EXEC sp_addrolemember N'db_datawriter', N'$UserName'" #Invoke-ExecuteSqlNonQuery -ConnString $ConnString -sql $sql #$sql = "EXEC sp_addrolemember N'db_ddladmin', N'$UserName'" #Invoke-ExecuteSqlNonQuery -ConnString $ConnString -sql $sql #$sql = "EXEC sp_addrolemember N'db_owner', N'$UserName'" #Invoke-ExecuteSqlNonQuery -ConnString $ConnString -sql $sql $sql = "GRANT CREATE FUNCTION TO [$UserName]" Invoke-ExecuteSqlNonQuery -ConnString $ConnString -sql $sql $sql = "GRANT CREATE PROCEDURE TO [$UserName]" Invoke-ExecuteSqlNonQuery -ConnString $ConnString -sql $sql $sql = "GRANT CREATE TABLE TO [$UserName]" Invoke-ExecuteSqlNonQuery -ConnString $ConnString -sql $sql $sql = "GRANT CREATE VIEW TO [$UserName]" Invoke-ExecuteSqlNonQuery -ConnString $ConnString -sql $sql #$sql = "GRANT CONTROL ON SCHEMA::[sde] TO [$UserName]" #Invoke-ExecuteSqlNonQuery -ConnString $ConnString -sql $sql #$sql = "GRANT CONTROL ON SCHEMA::[dbo] TO [$UserName]" #Invoke-ExecuteSqlNonQuery -ConnString $ConnString -sql $sql #$sql = "GRANT INSERT,UPDATE,DELETE,SELECT to [$UserName]" #Invoke-ExecuteSqlNonQuery -ConnString $ConnString -sql $sql #$sql = "GRANT CREATE XML SCHEMA COLLECTION to [$UserName]" #Invoke-ExecuteSqlNonQuery -ConnString $ConnString -sql $sql } function Invoke-ExecuteSqlNonQuery { [CmdletBinding()] param( [System.String] $ConnString, [System.String] $sql ) if($null -ne $sql -and $sql.Length -gt 0) { [System.Data.SqlClient.SqlConnection]$conn = New-Object System.Data.SqlClient.SqlConnection -ArgumentList $ConnString Try { $conn.Open() [System.Data.SqlClient.SqlCommand]$command = $conn.CreateCommand() $command.Connection = $conn $command.CommandText = $sql $command.CommandTimeout = 180 # Database creation doesn't complete within 30 seconds $command.CommandType = [System.Data.CommandType]::Text [void]$command.ExecuteNonQuery() } finally { if($conn){ try { $conn.Close() } catch{ } } } } } function Invoke-ExecuteSqlScalar { [CmdletBinding()] [OutputType([System.Int32])] param( [System.String] $ConnString, [System.String] $sql ) ### TODO:- SQL Injection Validation $result = -1 if($null -ne $sql -and $sql.Length -gt 0) { [System.Data.SqlClient.SqlConnection]$conn = New-Object System.Data.SqlClient.SqlConnection -ArgumentList $ConnString Try { $conn.Open() [System.Data.SqlClient.SqlCommand]$command = $conn.CreateCommand() $command.Connection = $conn $command.CommandText = $sql $command.CommandType = [System.Data.CommandType]::Text $result = $command.ExecuteScalar() } finally { if($conn){ try { $conn.Close() } catch{ } } } } $result } function Get-DatabaseConnectionString { [CmdletBinding()] [OutputType([System.String])] param( [System.String] $Server, [System.String] $Database, [System.Management.Automation.PSCredential] $Credential, [switch] $UseIntergratedSecurity ) $str = "Data Source=$Server;User ID=$($Credential.UserName);Password=$($Credential.GetNetworkCredential().Password)" if($Database -and $Database.Length -gt 0) { $str += ";Initial Catalog=$Database" } if($UseIntergratedSecurity) { $str += ";Intergrated Security=true" } $str } Export-ModuleMember -Function @( "Invoke-CreateMSSQLSDEIfNotExist" ) |