1

Redacted script based on this article: SQL Server Authentication Using a Virtual Drive

# Set the SQL Server instance name and database name
$SqlServerInstance = 'myServer.MyDomain.local\myInstance'
$DriveRoot = "SQLSERVER:\SQL\$SqlServerInstance"
$DatabaseName = "myDb"

# Set the SQL Server credentials Hint: user in pps = tx-export-sql  
function sqldrive  
{  
    param( [string]$driveName, [string]$login = "MyLogin", [string]$root = "SQLSERVER:\SQL\MyComputer\MyInstance" )  
    $password = read-host -AsSecureString -Prompt "Password"  
    $credential = new-object System.Management.Automation.PSCredential -argumentlist $login,$password  
    New-PSDrive $driveName -PSProvider SqlServer -Root $root -Credential $credential -Scope 1  
    # New-PSDrive WindowsAuth -PSProvider SqlServer -Root $root -Scope 1  # Windows Auth
}  
  
## Use the sqldrive function to create a SQLAuth virtual drive.  
sqldrive SQLAuth 'MyLogin' $DriveRoot

## Set-Location to the virtual drive, which invokes the supplied authentication credentials.  
Set-Location "SQLAuth:\Databases\$DatabaseName\Schemas"

From the Set-Location, I get an error message [redacted]: SQL Server PowerShell provider error: Could not connect to 'myServer.MyDomain.local\myInstance**+MyLogin**'. [Failed to connect to server myServer.MyDomain.local. --> 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) --> The system cannot find the file specified.]

version info Powershell 7.2.9 SqlServer 2019

I did a successful test with the created $credential object using a Invoke-Sqlcmd statement to rule out problems with credentials and rights.

If Set-Location is succesful a Get-ChildItem will list all the schemas in the database. I have tried this with WindowsAuth (by not including a credential for the PSDrive) and that works fine.

Is the "+MyLogin" in the "Could not connect to"-part of the error message something to worry about?

End-Goal: Trying to use the scripting capabilities of the SqlServer Powershell Module

I think I need a PSDrive for this (oversimplified):

 foreach ($ObjectType in Get-ChildItem -Path SqlInstance:\Databases\$DatabaseName) {
      foreach ($Object in Get-ChildItem -Path $($ObjectType.PSPath)) {
         $Object.Script() | Out-File -Filepath (New-Item -Path $ObjectPath -Force) -Encoding utf8NoBOM
      }
}

New script (with redactions):

$ErrorActionPreference = "Stop"
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls11 -bor [System.Net.SecurityProtocolType]::Tls12

# Import the SQLServer module
Import-Module SqlServer

# Set the SQL Server instance name and database name
$SqlServerInstance = "servername\instancename"
$DriveRoot = "SQLSERVER:\SQL\$SqlServerInstance"
$DatabaseName = "dbname"

# Set the SQL Server credentials
if (-not $Credential) {
    $Credential = Get-Credential
}

# Test SQL Server credentials
Invoke-Sqlcmd -ServerInstance $SqlServerInstance -Database $DatabaseName -Credential $Credential -Query "SELECT TOP (20) [name] FROM [sys].[schemas]" | Out-String

# recreate PSDrives
$drive = 'windrv'
if (Get-PSDrive | Where-Object Name -eq $drive) {
    Write-Output "Remove PSDrive '$drive'"
    Remove-PSDrive $drive
}

$drive = 'sqldrv'
if (Get-PSDrive | Where-Object Name -eq $drive) {
    Write-Output "Remove PSDrive '$drive'"
    Remove-PSDrive $drive
}

New-PSDrive "windrv" -PSProvider SqlServer -Root $DriveRoot                         # Windows authentication
New-PSDrive "sqldrv" -PSProvider SqlServer -Root $DriveRoot -Credential $Credential # Sql authentication

Write-Output "Root value for sqldrv looks funny ..."
Get-PSDrive 'windrv', 'sqldrv' | Select-Object "Name", "Root"

Write-Output "Test PSDrive 'windrv' Getting database schemas ..."
Get-ChildItem -Path windrv:\Databases\$DatabaseName\Schemas

Write-Output "Test PSDrive 'sqldrv' Getting database schemas ..."
Get-ChildItem -Path sqldrv:\Databases\$DatabaseName\Schemas

Output:


name
----
dbo
guest
INFORMATION_SCHEMA
sys
dsa
dfc
db_owner
db_accessadmin
db_securityadmin
db_ddladmin
db_backupoperator
db_datareader
db_datawriter
db_denydatareader
db_denydatawriter


Remove PSDrive 'windrv'

Name           Used (GB)     Free (GB) Provider      Root                                                                                                                                                CurrentLocation 
----           ---------     --------- --------      ----                                                                                                                                                --------------- 
windrv                                 SqlServer     SQLSERVER:\SQL\servername\…
sqldrv                                 SqlServer     SQLSERVER:\SQL\servername\…
Root value for sqldrv looks funny ...

Name : windrv
Root : SQLSERVER:\SQL\servername\instancename


Name : sqldrv
Root : SQLSERVER:\SQL\servername\instancename+sqluser

Test PSDrive 'windrv' Getting database schemas ...

Name : dfc


Name : dsa

Test PSDrive 'sqldrv' Getting database schemas ...
Get-ChildItem: myscript.ps1:43:1
Line |
  43 |  Get-ChildItem -Path sqldrv:\Databases\$DatabaseName\Schemas
     |  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     | Cannot retrieve the dynamic parameters for the cmdlet. SQL Server PowerShell provider error: Could not connect to 'servername\instancename+sqluser'. [Failed to connect to server servername. 
     | --> 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) --> The system cannot find the file specified.]

  • Why are you not using Invoke-SQL? Some networks do not allow an unencrypted username/password and require a credential. The cmdlet you are trying to use will not bypass the credentials. You can use stored procedures from invoke-sql. You can also use the command line utility sqlcmd.exe : https://learn.microsoft.com/en-us/sql/tools/sqlcmd/sqlcmd-utility?view=sql-server-ver16 – jdweng Mar 24 '23 at 12:22
  • 1
    @jdweng My endgoal is iterate over all objects in a database and script them as separate sql-files. over-simplified code: ``` foreach ($ObjectType in Get-ChildItem -Path SqlInstance:\Databases\$DatabaseName) { foreach ($Object in Get-ChildItem -Path $($ObjectType.PSPath)) { $Object.Script() | Out-File -Filepath (New-Item -Path $ObjectPath -Force) -Encoding utf8NoBOM } } ``` I can't seem to connect a PSDrive "SqlInstance" with SQL authentication. – Marco Jansen Mar 24 '23 at 12:50
  • Connect to server using SQL Server Management Studio and check log files using explorer under management. You should see the user/group the attempted the failed login. It should be the same as when you successfully connected. If there is not login than windows blocked the connection due to the username/password. Server ahs two types of credentials shown on SSMS login window 1) Windows 2) SQL You can try connection with SSMS wit SQL option. If fails you need an admin to change the setting in SSMS. The failure will tell what account need to be changed. – jdweng Mar 24 '23 at 14:33
  • 1
    The Named Pipes Provider needs additional ports open to access remote SQL Servers. If you have the SQL Server (version) Configuration Manager tool installed try checking the client protocols (both 32 bit and 64 bit) to ensure that TCP/IP is enabled and, optionally, disable the Named Pipes protocol to ensure it isn't getting in the way. Otherwise try using the `cliconfg` tool to do the same on the General tab. If it's still not working you can create an Alias for the remote server and configure it specifically to use the TCP/IP protocol. – AlwaysLearning Mar 24 '23 at 14:43
  • @AlwaysLearning : You are getting too complicated. Start with the simple normal issues. 99% of connection issues with SQL Server are the credentials. – jdweng Mar 24 '23 at 14:49
  • It's not a login error, @jdweng, it's an RPC port mapper error because it can't connect using the Named Pipes Provider. – AlwaysLearning Mar 24 '23 at 14:53
  • @AlwaysLearning : the error says "The server was not found or was not accessible". It more likely a TLS failure due to a certificate issue. – jdweng Mar 24 '23 at 15:03
  • @AlwaysLearning The Named Pipes protocol is disabled on the SqlServer instance I think this is the last protocol used by the client. – Marco Jansen Mar 24 '23 at 16:06
  • @jdweng: I looked at the SQL Server Logs. I don't see succesful logins listed in the log and hardly any failed ones. I've tested the SqlAuth credentials both in SSMS and in pwsh with success and these are not logged. It seems only failed logons are logged. I will add a new script where the same credentials succeed for Invoke-Sqlcmd but fail for New-PSDrive. The drive is created but can't be used because of connection issues. The Root property has the username appended. Is that normal? – Marco Jansen Mar 24 '23 at 16:19
  • Check the Report Server Logs. The SSRS has different credentials that the SQL Server. The SSRS logs are in the Window Start Menu on the server machine. SSRS you log into the Report Service and then it make a connection to the DataBase. – jdweng Mar 24 '23 at 17:04
  • @jdweng: SSRS is not installed on the SQL Server. – Marco Jansen Mar 27 '23 at 08:41
  • Looks like PSDrive just does not work with SQL-credentials. It tries to connect with a invalid instancename : Root : SQLSERVER:\SQL\servername\instancename+sqluser The +sqluser should not be part of the instancename. – Marco Jansen Mar 27 '23 at 08:44
  • I would check Event Viewer in both client and server and see if any errors occurred. It sounds like you are using wrong instance of database, wrong port number, or a certificate is wrong since you are not seeing any log messages. – jdweng Mar 27 '23 at 09:57
  • No solution for Sql credentials. Switched Windows credentials. Used Start-Job to set the credentials. – Marco Jansen Mar 31 '23 at 15:06

0 Answers0