Changing privileges on multiple SQL server tables for a user

This is not really a Dynamics AX thing but with BI in mind it kind of relates.

The thing is that sometimes you have users that needs access to AX tables and views on the SQL server to maintain and develop BI. And often these users should have access to almost every table except a few. Payroll tables are a good example.

In a normal situation you would use schemas to handle this but since AX creates all tables as part of the dbo schema this is not an option. So I created this little script for a colleague to accelerate the proces:

DECLARE @sqlStatement NVARCHAR(max)
DECLARE @user NVARCHAR(30)
DECLARE @filter NVARCHAR(10)

-- ==========
-- Initialize 
-- ==========

SET @sqlStatement = '';
SET @user = 'contoso\abc';
SET @filter = 'payroll%';

-- ================
-- Get REVOKE lines
-- ================

SELECT @sqlStatement = @sqlStatement + 'REVOKE SELECT ON [' + NAME + '] TO [' + @user + '];' FROM SysObjects WHERE (TYPE = 'U' OR TYPE = 'V')

-- ================
-- Get GRANT lines
-- ================

SELECT @sqlStatement = @sqlStatement + 'GRANT SELECT ON [' + NAME + '] TO [' + @user + '];' FROM SysObjects WHERE (TYPE = 'U' OR TYPE = 'V') AND NAME NOT LIKE '' + @filter + ''

-- ==============================
-- Execute privilege change query
-- ==============================

EXECUTE sp_executesql @sqlStatement;

What it does is that first it creates 3 variables. One for an SQL statement, one for the user identity and one for filtering what tables NOT to grant access to. In this case we want user ABC in the contoso domain to have SELECT rights on all tables except those beginning with “Payroll”.

It then starts by creating the REVOKE SELECT statements for all tables and views (User tables only) and adds them to the @sqlStatement variable.

Then it traverses through the tables and views to make the GRANT SELECT part on all tables NOT matching the filter in the @filter variable.

Finally the created statement is executed using the sp_executesql stored procedure.

It is not the fastest statement in the world; but it gets the job done.

Troubleshooting AX/SSRS

The purpose of this document is to list a troubleshoot path to follow when reports cannot be printed from AX 2012.

The contents are not fully covering all options available but points out a toolbox for handling often seen issues.

Troubleshooting

Is it all reports not printing?

Try printing one of the most simple reports available. I usually use the Departments report found in “Organization administration / Reports / Base data / Departments”. If that one prints successfully it is probably not the SSRS causing the problem.

Is SSRS set up correct within AX?

AX has a very flexible setup regarding SSRS. Each AOS has – and must have – its own relation to an SSRS. All AOS’s can point towards the same SSRS but it is also possible to address the reports from each AOS to its own SSRS instance. One AOS can on top this have multiple relations to different SSRS instances. However, only one relation can be default and active.
So how do we make sure all this works?
1. Make sure that all AOS servers have a relation (with default mark set) to an SSRS instance in the SSRS list (Appendix 1 – Locating the SSRS names)
2. Validate the relations using the “Validate settings” button.
3. Verify that the specified URLs are valid.

Is SSRS set up correct regarding connection to AX?

With AX pointing towards the right SSRS instance we need to make sure that the SSRS instance points towards a valid AOS. With only one SSRS instance on the server it – by default – looks up the default client configuration on the server to access AX. Having multiple SSRS instances on one server requires each instance to have an configuration file with the name Microsoft.Dynamics.AX.ReportConfiguration.axc. Make sure that this configuration file is valid. For instance by opening a client with it if possible. Also make sure that the WCF part of the file is fully updated. To rebuild the WCF part follow the description in the section Rebuild the WCF part of the AX configuration for the SSRS.
Another way to test that multiple instances points towards the correct instances is to create eg. a department called “Development” in a development environment and one called “Test” in the test environment and then verify that these are shown when printing from the relevant AX environments or the SSRS report manger site (see description of how to print from outside the AX client).

Does it print from outside the AX client?

SSRS offers a web frontend allowing us to test – at least some – reports from outside AX pretty easily. To do so you need to find the URL address to the report manager site. This is listed in the Report server list found within AX. To find this list please read the description in Appendix 1 – locating the SSRS names.
From here navigate to the URL specified in the field Report Manager URL.
If this does not open up succesfully go directly to restarting the SSRS service.
aIf it opens up successfully click on the DynamicsAX folder and use the Search field in the upper right corner to locate the report design HcmDepartmentReport.DepartmentDesign

Printing reports from the SSRS Report Manager

Printing reports from the SSRS Report Manager

Click on the report to show it. If a report is shown the report server and the connection works.
If not printed successfully you might be presented with an error description pointing you in a useful direction.
Rebuild the WCF part of the AX configuration for the SSRS
The WCF part of the AX configuration describes the service ports available. It can be usefull to rebuild these in some circumstances eventhough you do not think they have been altered. To update this open the Microsoft Dynamics AX Client Configuration on the server running the SSRS. Click Manage and “Open a configuration file…”. Navigate to C:\Program Files\Microsoft SQL Server\MSRS11.<Name of the relevant instance>\Reporting Services\ReportServer\bin and select the file Microsoft.Dynamics.AX.ReportConfiguration.axc.

Rebuild the WCF part of the configuration file

Rebuild the WCF part of the configuration file

On the Connection tab click the Refresh Configuration button and wait …

Waiting for the WCF to be rebuild.

Waiting for the WCF to be rebuild.

When completed click Apply and “Manage / Save configuration file”.
After saving the file restart the SSRS-service.

Appendix 1

Locating the SSRS names

The name of the server can be found from within AX by looking up the reporting server(s) listed in “System administration / Setup / Business intelligence / Report servers”.
Notice, that the list can contain multiple SSRS instances and not all of them are related to the environment you are trying to fix.

Restart the SSRS-service

This is a fairly quick service when it comes to restarting so you will not be troubling users for that many seconds.
Log on to the server running SSRS. From here locate the service “SQL Server Reporting Services (<Name of the relevant instance>)” and restart it.

Joins, indexes and an example of when they don’t match…

We experienced some data locks that gave a customer some performance issues. Going through the motions we found this statement (scrambled) being the problem:

update_recordSet adjustment
    setting Voucher = voucher
    where ! adjustment.voucher
        join trans
            where trans.Status == Status::Open
               && trans.DateTime < perDateTime
               && trans.RecId == adjustment.Trans;

The table Adjustment is connected to the table Trans through a relation like this: Adjustment.Trans = Trans.RecId. And Adjustment has – among others – an unclustered index like this: Trans, Voucher and a couple of other fields.

So you might think that the SQL server was capable of utilising this index since both Trans and Voucher are in play in the attempt to limit the records involved.

Looking at it from the SQL server it ends up like this:

(@P1 NVARCHAR(21), @P2 INT, @P3 BIGINT, @P4 NVARCHAR(5), @P5 NVARCHAR(21), @P6 BIGINT, @P7 NVARCHAR(5), @P8 INT, @P9 DATETIME2) UPDATE T1
SET VOUCHER = @P1, RECVERSION = @P2
FROM ADJUSTMENT T1
CROSS JOIN TRANS T2
WHERE (((T1.PARTITION = @P3)
AND (T1.DATAAREAID = @P4))
AND ((T1.VOUCHER = @P5)))
AND (((T2.PARTITION = @P6)
AND (T2.DATAAREAID = @P7))
AND (((T2.STATUS = @P8)
AND (T2.DATETIME < @P9))
AND (T2.RECID = T1.TRANS)))

Now, when executing this ended up giving an index scan resulting in heavy locking of data. The reason for this – and the reason why the index could not be used – is that the SQL server sees this as two statements selecting adjustment records with the Voucher field as only range and the trans records with the specified ranges except the relation range and then returns the intersection of these two result sets.

Adding an index with Voucher as first field solves the problem and the data locking stops.

Change installation folder for the AOS server

Working for a company that handles development of multiple modules/add-ons to AX we end up having a lot of AOS-services on one server. We do that to separate development and release environments and keeping modules isolated from each other.

The problem that we sometimes end up with is that the C-drive reaches max and we need to install some of the AOS services on a different drive.

Going through the normal setup routine does not offer any options of specifying the installation folder. So we need to do two modifications before it works.

First step is to open the regedit.exe and navigate to HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Dynamics\6.0\Setup\Components\InstallDir and change the value to where you would like the AOS to be installed.

Second step is to make sure that the Server Setup files is present in the new directory. To do this simply copy the folder C:\Program Files\Microsoft Dynamics AX\60\SetupSupport to the new drive so you have a D:\Program Files\Microsoft Dynamics AX\60\SetupSupport or wherever you want the AOS servers installed.

Run the AX setup and your AOS is now installed on your new drive.

Roaming AUC files – new feature in R3

The quest for increasing performance in AX appears never-ending. With AX 2012 R3 Microsoft has added a new tool allowing us to make the AUC files global/shared.

Basic AUC file info:

AUC files are cache files made by the AX client to improve load time. Forms we have already loaded once could be loaded again from the cache without having to make a trip to the AOS for the bits and bytes. All stored in c:\users\<username>\AppData\local and then by nature user specific.

So the main challenge so far has been that user A opens the sales order form the first time, waits, caches the element and can open the form faster the second time and the same story for user B, C and all the others.

In AX 2012 R3 a new feature have been added to the client configuration with the title “Use roaming user profile to store client-side cache”. That basically says it all. We can now specify a global directory for the cache files allowing users to share the cache so when user A has opened the form user B can utilise the cache.

Still no fun for user A, but user B is in luck …