Grant read permission for MSysObjects - powershell

I need to get the metadata of some hundred MS Access DBs, so I need to automate the process of metadata gathering.
I want to query stuff described here, but before I can query the DBs I need read access to MSysObjects tables.
I Keep getting following error:
Record(s) cannot be read; no read permission on 'MsysObjects'.
so I dug deeper:
I've read the article about similar issues in the C# section (see here and also this one).
I put together a simple script which works well for creating tables and so on, but I am having problems to setup the read access.
$ScrUsr = $(whoami)
Write-Host $ScrUsr
$cmd = "GRANT SELECT ON MSysObjects TO [$ScrUsr]"
Write-Host $cmd
Function Invoke-ADOCommand($Db)
{
$connection = New-Object -ComObject ADODB.Connection
$connection.Open("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=$db;" )
$command = New-Object -ComObject ADODB.Command
$command.ActiveConnection = $connection
$command.CommandText = $cmd
$rs = $command.Execute()
$connection.Close()
}
$Db = "C:\Temp\test1.accdb"
Invoke-ADOCommand -db $Db
Executing the Script throws me following Error reason:
Cannot open the Microsoft Office Access database engine workgroup information file.
How can I allow read permission on MSysObjects?

There are two issues you must address:
Your code will use the Access security account "Admin" when interacting with the Access ACCDB database. Other Access security accounts are only available if you have implemented Access user-level security (ULS), but that feature is only available for MDB format databases. Therefore, with ACCDB, you can't GRANT anything to any account other than "Admin".
You must include the location of the "System database" in your connection string.
If you don't know where to find the System database, open Access and check the output from this statement in the Immediate window. (Ctrl+g will open the Immediate window)
Debug.Print Application.DBEngine.SystemDb
My System database is C:\Users\hans\AppData\Roaming\Microsoft\Access\System1.mdw Substitute yours in the code example below.
I'm not really proficient with Powershell, but this example ran without error for me. (Be sure to change both $Db and $SystemDb.)
$ScrUsr = $(whoami)
Write-Host $ScrUsr
$cmd = "GRANT SELECT ON MSysObjects TO Admin;"
Write-Host $cmd
Function Invoke-ADOCommand($Db, $SystemDb)
{
$connection = New-Object -ComObject ADODB.Connection
$ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=$db;Jet OLEDB:System database=$SystemDb;"
Write-Host $ConnectionString
$connection.Open($ConnectionString)
$discard = $connection.Execute($cmd)
$connection.Close()
}
$Db = "C:\Users\hans\AccessApps\Sample.accdb"
$SystemDb = "C:\Users\hans\AppData\Roaming\Microsoft\Access\System1.mdw"
Invoke-ADOCommand -db $Db -SystemDb $SystemDb

Related

PowerShell - Connect and disconnect from SPO

The script connects to SPO and read from excel. At the end I close the local excel instance and disconnect from SPO. Usually I am running the script so this is really necessary to do it every run? connect ad disconnect. Maybe there is another way to do it? ask if there is a valid active connection?
I saw that if the credentials are wrong for example the script is still reading from the sheet maybe from the memory, how can I protect from this scenario?
#Connecting to SharePoint Online site
Write-host "Connecting to SharePoint Online"
Connect-PnPOnline -Url $SharePointSiteURL # -Credentials $PSCredentials
$ExcelObject = New-Object -ComObject Excel.Application
$ExcelWorkBook = $ExcelObject.Workbooks.Open($SharePointSiteURL)
$ExcelWorkSheet = $ExcelWorkBook.Sheets.Item("VIP List")
function QuitExcel {
# when done, quit Excel and remove the used COM objects from memory (important)
$ExcelWorkBook.Close()
$ExcelObject.Quit()
$null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($ExcelWorkSheet)
$null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($ExcelWorkBook)
$null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($ExcelObject)
[System.GC]::Collect()
[System.GC]::WaitForPendingFinalizers()
Disconnect-PnPOnline

Powershell script unable to decrypt password from Jenkins withCredentials()

I created a powershell script to run DB2 queries in Jenkins
withCredentials([usernamePassword(credentialsId: 'cred-id', usernameVariable: 'ID', passwordVariable: 'PASSWORD')]) {
$cn = new-object system.data.OleDb.OleDbConnection("Server=Server; Provider=IBMDADB2;DSN=DBName;User Id=$ID;Password=$PASSWORD");
$ds = new-object "System.Data.DataSet" "ds"
$q = "myQuery"
$da = new-object "System.Data.OleDb.OleDbDataAdapter" ($q, $cn)
$da.Fill($ds)
$cn.close()
}
If I run the script and hard code my credentials, it run fine.
With withCredentials(), I am getting the following error: Security processing failed with reason "15" ("PROCESSING FAILURE")
From some research, the error seems to be because DB2 can't handle encrypted data. Is there a way to overcome this error?
EDIT:
I tried to add
$SecurePassword = ConvertTo-SecureString $PASSWORD -AsPlainText -Force
$BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecurePassword)
$UnsecurePassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)
at the beginning of my powershell script, but it still throws the same error even though the credential work fine if used in plain text
If I understand the docs for the Credentials Binding Jenkins plugin correctly, the variables designated in the withCredentials() call become environment variables, so as to enable their use across process boundaries.
Note that the values of these environment variables are not encrypted, so no extra (decryption) effort is required on the part of the target process.
Therefore, you need to use $env:[1] instead of just $ to refer to these variables in PowerShell:
$cn = new-object system.data.OleDb.OleDbConnection "Server=Server; Provider=IBMDADB2;DSN=DBName;User Id=$env:ID;Password=$env:PASSWORD"
[1] See the conceptual about_Environment_Variables help topic.

Cannot use Azure SQL with Azure DevOps Server 2019 - (Azure Government)

I have been struggling to get my DevOpsServer 2019-RC1 installation to see my Azure SQL Server
My DevOpsServer install is on an Azure VM, as recommended
I have implemented everything from the below documentation regarding the set up of an MSI for the VM, and granting the MSI access to Azure SQL via AAD authentication:
https://learn.microsoft.com/en-us/tfs/server/install/install-azure-sql
I have also added the VNET where the VM NIC is located, as a VNET firewall rule on the Azure SQL Server to ensure there are no connection issues
My DevOpsServer refuses to see the Azure SQL Server or its databases
To confirm that Azure SQL is not blocked from the VM, I successfully created an ODBC system DSN connection on the VM, which allows me to see the Azure SQL Server, and its Databases
Per the reference documentation:
When setting up a new DevOps Server instance, i selected "This is a
new Azure DevOps Server deployment"
On the Database page of the configuration wizard, specify the Azure SQL
Database server instance, typically in the form of
"SQLInstanceName.database.windows.net"
Please let me know if there is anything else i can do to help the Devops Server Configuration Wizard see my Azure SQL Server and Databases
PS I am trying to get this working in Azure Government (MAG) if this changes the capability...
Error received when attempting to connect to the SQL Database programmatically via the following Powershell script:
# Retrieve the access token
$response = Invoke-WebRequest -Uri 'http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https%3A%2F%2Fdatabase.usgovcloudapi.net' -Method GET -Headers #{Metadata="true"}
$content = $response.Content | ConvertFrom-Json
$AccessToken = $content.access_token
# Create the connection
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "Data Source = test-sqlsrv.database.usgovcloudapi.net; Initial Catalog = inldb"
$SqlConnection.AccessToken = $AccessToken
$SqlConnection.Open()
# Send a Query
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.CommandText = "SELECT * from <TABLE>;"
$SqlCmd.Connection = $SqlConnection
$SqlAdapter = New-Object System.Data.SqlClient.SqlDataAdapter
$SqlAdapter.SelectCommand = $SqlCmd
$DataSet = New-Object System.Data.DataSet
$SqlAdapter.Fill($DataSet)
Try running ALTER USER [VMName] WITH DEFAULT_SCHEMA=dbo from both the collection and config DBs. I have a PR out to add this to the documentation and this might be causing your issue.
Try connecting to the SQL instance via Powershell instead of Azure DevOps Server.
You can run the following script to do that:
# Retrieve the access token
$response = Invoke-WebRequest -Uri 'http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https%3A%2F%2Fdatabase.windows.net%2F' -Method GET -Headers #{Metadata="true"}
$content = $response.Content | ConvertFrom-Json
$AccessToken = $content.access_token
# Create the connection
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "Data Source = <AZURE-SQL-SERVERNAME>; Initial Catalog = <DATABASE>"
$SqlConnection.AccessToken = $AccessToken
$SqlConnection.Open()
# Send a Query
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.CommandText = "SELECT * from <TABLE>;"
$SqlCmd.Connection = $SqlConnection
$SqlAdapter = New-Object System.Data.SqlClient.SqlDataAdapter
$SqlAdapter.SelectCommand = $SqlCmd
$DataSet = New-Object System.Data.DataSet
$SqlAdapter.Fill($DataSet)
This should at least give you a more descriptive error to debug.
Gvazzana, I also recommend testing with the script danwkennedy provided, but be sure to change database.windows.net to database.usgovcloudapi.net for Azure Government.
I would pay close attention to any errors around obtaining an access token and errors associated with opening the SQL connection.
If nothing's standing out is it possible to capture a Fiddler trace?
I agree that you should perform the PowerShell test to test your MSI. It looks like you are having issues reaching the IP to get the access token. If you are attempting to connect from a Government network, it is likely that you are going through some type of web proxy service (Blue Coat, etc.) to get to the internet. You can maybe trick the proxy by emulating the user agent string from a browser by using the -UserAgent parameter on your Invoke-WebRequest command.
If that doesn't work, you may need to reach out to your proxy team to troubleshoot the issue.
Lastly, if you are able to test successfully in PowerShell, but you still get the connection test error in the DevOps install, make sure to follow the steps here:
https://learn.microsoft.com/en-us/tfs/server/install/install-azure-sql
I forgot to add the user to the master DB... Once I did that, everything worked. Good luck.
You can access to your Azure Devops database with your Windows Authentication level. So your Windows login user should have configured sysadmin privilege in your database (e.g Microsoft SQL server)

How to run Powershell script on local computer but with credentials of a domain user

I have to implement a solution where I have to deploy a SSIS project (xy.ispac) from one machine to another. So far I've managed to copy-cut-paste the following stuff from all around the internet:
# Variables
$ServerName = "target"
$SSISCatalog = "SSISDB" # sort of constant
$CatalogPwd = "catalog_password"
$ProjectFilePath = "D:\Projects_to_depoly\Project_1.ispac"
$ProjectName = "Project_name"
$FolderName = "Data_collector"
# Load the IntegrationServices Assembly
[Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.Management.IntegrationServices")
# Store the IntegrationServices Assembly namespace to avoid typing it every time
$ISNamespace = "Microsoft.SqlServer.Management.IntegrationServices"
Write-Host "Connecting to server ..."
# Create a connection to the server
$sqlConnectionString = "Data Source=$ServerName;Initial Catalog=master;Integrated Security=SSPI;"
$sqlConnection = New-Object System.Data.SqlClient.SqlConnection $sqlConnectionString
$integrationServices = New-Object "$ISNamespace.IntegrationServices" $sqlConnection
$catalog = $integrationServices.Catalogs[$SSISCatalog]
# Create the Integration Services object if it does not exist
if (!$catalog) {
# Provision a new SSIS Catalog
Write-Host "Creating SSIS Catalog ..."
$catalog = New-Object "$ISNamespace.Catalog" ($integrationServices, $SSISCatalog, $CatalogPwd)
$catalog.Create()
}
$folder = $catalog.Folders[$FolderName]
if (!$folder)
{
#Create a folder in SSISDB
Write-Host "Creating Folder ..."
$folder = New-Object "$ISNamespace.CatalogFolder" ($catalog, $FolderName, $FolderName)
$folder.Create()
}
# Read the project file, and deploy it to the folder
Write-Host "Deploying Project ..."
[byte[]] $projectFile = [System.IO.File]::ReadAllBytes($ProjectFilePath)
$folder.DeployProject($ProjectName, $projectFile)
This seemed to be working surprisingly well on the development machine - test server pair. However, the live environment will be a bit different, the machine doing the deployment job (deployment server, or DS from now on) and the SQL Server (DB for short) the project is to be deployed are in different domains and since SSIS requires windows authentication, I'm going to need to run the above code locally on DS but using credentials of a user on the DB.
And that's the point where I fail. The only thing that worked is to start the Powershell command line interface using runas /netonly /user:thatdomain\anuserthere powershell, enter the password, and paste the script unaltered into it. Alas, this is not an option, since there's no way to pass the password to runas (at least once with /savecred) and user interactivity is not possible anyway (the whole thing has to be automated).
I've tried the following:
Simply unning the script on DS, the line $sqlConnection = New-Object System.Data.SqlClient.SqlConnection $sqlConnectionString would use the credentials from DS which is not recognized by DB, and New-Object does not have a -Credential arg that I could pass to
Putting everything into an Invoke-Command with -Credential requires using -Computername as well. I guess it would be possible to use the local as 'remote' (using . as Computername) but it still complains about access being denied. I'm scanning through about_Remote_Troubleshooting, so far without any success.
Any hints on how to overcome this issue?
A solution might be to use a sql user (with the right access rights) instead of an AD used.
Something like this should work.
(Check also the answer to correct the connection string)

how to connect oracle database and run query by powershell

How can I connect to an Oracle database (11g)? I have a list of oracle servers and I want to execute a query on them from Jump Server (the Jump server has Powershell v2).
Servers are accessible from Jump Server as I am able to access them by UNC path.
Update:
I know it can be done by using ODP.Net connector. But i don't want to use it due to approval.
You can try the method using an OleDbConnection described here
function Get-OLEDBData ($connectstring, $sql) {
$OLEDBConn = New-Object System.Data.OleDb.OleDbConnection($connectstring)
$OLEDBConn.open()
$readcmd = New-Object system.Data.OleDb.OleDbCommand($sql,$OLEDBConn)
$readcmd.CommandTimeout = '300'
$da = New-Object system.Data.OleDb.OleDbDataAdapter($readcmd)
$dt = New-Object system.Data.datatable
[void]$da.fill($dt)
$OLEDBConn.close()
return $dt
}