I recently ran into a situation where one of our users was seeing all the data in our SSAS tabular cube/model. Yes, they were in the AD group specified in the Role, but they were also not an SSAS Admin. It seemed like the role wasn't even being taken into account when the user logged in.
I couldn't find anything on the internets to pinpoint the issue, so I'm writing it up in case anyone else runs into this.
As far as I knew the only reason the role would get skipped was if the user was an SSAS Admin, which like I said they weren't.
Running a SQL Profiler of the SSAS instance and logging in to the cube as the user showed me a Session Initialize value of "*, model access" which means they had access to everything (*) and to our one role "Model Access" (if specifically selected).
If I ran it as me, an SSAS Admin, I got the same exact thing.
Running as a user who was not having access problems showed only access to "Model Access".
So how were they bypassing the role even though not specified as an SSAS Admin in the Analysis Server's properties?
Local Windows admin.
Somehow an AD group the user was in was included as a local admin on the Windows server of our SSAS service. And if you look in the SSAS Admin list the local Administrators group is not listed there, so it might not be the first thing you think of when troubleshooting this kind of access.
There is an Advanced Property in the Analysis Service instance's settings called Security > BuiltinAdminsAreServerAdmins. If you want to include all the local Admins to see all the contents of your SSAS cubes you can leave it enabled (true), but if those users are not the same users who should have full data access you will want to disable that option.
Bradley Schacht's blog post describes how to turn this off as well as the dangers of shutting it off before adding people/groups as SSAS Admins.
Hope this helps!
I've been working with computers for almost 30 years now. This blog contains some of my more useful tools and scripts - mainly so I can find them myself easily. Hopefully they are useful for others as well.
Wednesday, June 5, 2019
SSAS Role not Being Used
Labels:
Bypass,
Local Admin,
Role,
SSAS
Monday, June 18, 2018
Automatic Screen Capture 2.0
I have updated the Automatic Screen Capture utility to include something I've wanted to add for a long time but never got around to it: A prompt after unlocking my computer so I can make a note of what I was doing when away from my computer. This comes in handy when I've been working with a user or client away from my laptop but still need to know how to track my time.
Download here from OneDrive
Description:
A utility to create automatic screenshots. Multiple monitors supported.
I created this program to help me go back through my day to see what all I worked on.
This is freeware. No reverse-engineering or anything like that. Use at your own risk.
One known issue - it does not handle the larger Windows 8 DPI settings very well. That will be the next thing I tackle whenever I get back around to working on the program.
WARNING:
This is not intended to capture someone's screen without their knowledge.
I will not change it to hide the system tray icon nor the process in Task Manager.
How To:
Settings Screen
Notes:
If you stop the auto capture but do not fully exit the program, the settings window will pop up
after the interval specified in the Stop Reminder Interval. This is designed so you do not forget
to turn on the auto capture if you needed to stop it for a period of time but don't use snooze.
Version Info:
2.0
-------
Added inactivity notice and report to optionally track what non-computer work was done while the computer was locked
Added settings for configuring the inactivity notice
Rearranged config screen
1.8
-------
Fixed a bug when manually entering a save folder
Added a capture button on the Settings window
Added statistics of Captures vs Missed timed screenshots
Added About window
1.7
-------
Added Snooze functionality to the system tray
Updated system tray icons to show the current status of the auto-capture; yellow if snoozed, red of stopped
Various code streamlining
1.6
-------
Added Snooze functionality; use from the settings window; this will pause captures and stop warnings
The Set botton will turn yellow when settings have changed but are not Set
The Snooze button will turn yellow while snoozing
Added warnings for un-Set changes before starting capture or exiting the program
Setting window format update
1.5
-------
Added the Stop Reminder Interval
Added Start/Stop to the system tray
Added Settings to the system tray
Changed the system tray double-click to be a manual screenshot
Updated the message box when closing the program from the settings screen
1.0
-------
Original version
Future enhancements
-------
Program icon
System Tray icon
Monitor selection
Option to suppress screenshots when the computer is locked
Description:
A utility to create automatic screenshots. Multiple monitors supported.
I created this program to help me go back through my day to see what all I worked on.
This is freeware. No reverse-engineering or anything like that. Use at your own risk.
One known issue - it does not handle the larger Windows 8 DPI settings very well. That will be the next thing I tackle whenever I get back around to working on the program.
WARNING:
This is not intended to capture someone's screen without their knowledge.
I will not change it to hide the system tray icon nor the process in Task Manager.
How To:
Settings Screen
| Prefix | File name prefix |
| Suffix | File name suffix, including timestamp; currently this is not editable |
| Folder | Folder in which to save the screenshots |
| Compression | Percent to which to compress the image files |
| A lower number creates smaller files; a higher number is higher quality | |
| 20 percent is the lowest suggested value that is still readable | |
| Capture Interval | Amount of time between screenshots |
| Stop Reminder Interval | Amount of time between reminders if the auto capture is stopped |
| Notice Time | Amount of time the computer is locked before the inactive notice |
| prompt appears | |
| Notice Snooze Time | Amount of time to snooze the inactive notice after it appears |
| Enabled | Whether or not to utilize the inactive notice feature |
| Snooze | Snooze the capture and stop warnings |
| Set | Press to save and apply the settings |
| Start/Stop | Start or stop the auto capture |
| Minimize | Minimize the window to the system tray |
| Exit | Close the capture program |
| System Tray | |
| Double-click | Create a screenshot right now |
| Right-click | Settings | Open the settings window |
| Right-click | Start | Start or stop the auto capture |
| Right-click | Capture | Create a screenshow right now |
| Right-click | Snooze | Snooze for duration of selected time |
| Right-click | Exit | Close the program |
Notes:
If you stop the auto capture but do not fully exit the program, the settings window will pop up
after the interval specified in the Stop Reminder Interval. This is designed so you do not forget
to turn on the auto capture if you needed to stop it for a period of time but don't use snooze.
Version Info:
2.0
-------
Added inactivity notice and report to optionally track what non-computer work was done while the computer was locked
Added settings for configuring the inactivity notice
Rearranged config screen
1.8
-------
Fixed a bug when manually entering a save folder
Added a capture button on the Settings window
Added statistics of Captures vs Missed timed screenshots
Added About window
1.7
-------
Added Snooze functionality to the system tray
Updated system tray icons to show the current status of the auto-capture; yellow if snoozed, red of stopped
Various code streamlining
1.6
-------
Added Snooze functionality; use from the settings window; this will pause captures and stop warnings
The Set botton will turn yellow when settings have changed but are not Set
The Snooze button will turn yellow while snoozing
Added warnings for un-Set changes before starting capture or exiting the program
Setting window format update
1.5
-------
Added the Stop Reminder Interval
Added Start/Stop to the system tray
Added Settings to the system tray
Changed the system tray double-click to be a manual screenshot
Updated the message box when closing the program from the settings screen
1.0
-------
Original version
Future enhancements
-------
Program icon
System Tray icon
Monitor selection
Option to suppress screenshots when the computer is locked
Monday, May 16, 2016
SSAS Data Connection in Excel - Unable to connect to server
I just ran into a very odd situation trying to connect a user's Excel 2013 to a SQL Server Analysis Server using Data Connections. When setting up the Data Connection, it was acting as if the server wasn't there - an "unable to connect to server" or "server not found" sort of thing. Needless to say, spelling was checked, basic network connectivity was checked, and SSAS connectivity was successfully checked on another computer.
Additionally, the local firewall was turned off, a different user logged in and tried (and failed), the computer could ping the server, and even a SQL Server Data Connection in Excel to the same server worked.
I finally did a Repair on Office 2013 in Add/Remove programs (or, now, Uninstall a Program), and that did the trick. There must have been something corrupt in the components that handled the SSAS Data Connections.
Hope this helps anyone else who runs into this.
Additionally, the local firewall was turned off, a different user logged in and tried (and failed), the computer could ping the server, and even a SQL Server Data Connection in Excel to the same server worked.
I finally did a Repair on Office 2013 in Add/Remove programs (or, now, Uninstall a Program), and that did the trick. There must have been something corrupt in the components that handled the SSAS Data Connections.
Hope this helps anyone else who runs into this.
Labels:
Data Connection,
Excel,
Office 2013,
SSAS
Wednesday, October 14, 2015
Upgrade Progress Script v2
A few years ago I created a script (version 1) to see how far along Dynamics GP Utilities was in the process of upgrading company databases. If you've ever upgraded GP before you know the upgrade screen doesn't always refresh nor does it give any real indication of time. With the arrival of GP 2015, I needed to update my original script to work correctly. I figured it was also about time to give the script a major face-lift.
This script will now also take into account simultaneous company upgrades - using multiple GP clients to upgrade the company databases. (Tip: If you have a lot of GP companies to upgrade - or several large ones - using multiple clients to upgrade a subset of the companies can be a great way to reduce the upgrade time without affecting performance too much, providing the disk subsystem on the server can handle it.)
The estimated remaining time is based on the average completion time of companies that have completed so far. If you have only one GP company then this metric is pretty useless to you. If you have a few very small companies that already upgraded and the last one is your main company, the estimated time may be off by quite a bit, but you will still have some sort of idea how long it will take.
Special thanks to Lance Brigham for the upgrade statuses.
This script will now also take into account simultaneous company upgrades - using multiple GP clients to upgrade the company databases. (Tip: If you have a lot of GP companies to upgrade - or several large ones - using multiple clients to upgrade a subset of the companies can be a great way to reduce the upgrade time without affecting performance too much, providing the disk subsystem on the server can handle it.)
The estimated remaining time is based on the average completion time of companies that have completed so far. If you have only one GP company then this metric is pretty useless to you. If you have a few very small companies that already upgraded and the last one is your main company, the estimated time may be off by quite a bit, but you will still have some sort of idea how long it will take.
Special thanks to Lance Brigham for the upgrade statuses.
USE [DYNAMICS] DECLARE @NewVersion int DECLARE @NewBuild int SELECT @NewVersion = db_verMajor, @NewBuild = db_verBuild FROM DB_Upgrade WHERE PRODID = 0 AND db_name = 'DYNAMICS' IF object_id('tempdb..#Completed_List') IS NOT NULL BEGIN DROP TABLE #Completed_List END SELECT * INTO #Completed_List FROM ( SELECT Completed_Company = RTRIM(db_name), Started_At = (SELECT TOP 1 start_time FROM DB_Upgrade WHERE db_name = DBU.db_name and PRODID = 0), Ended_At = CASE WHEN (MIN(db_verOldMajor) <> @NewVersion OR MIN(db_verOldBuild) <> @NewBuild OR MIN(db_verOldMajor) <> MIN(db_verMajor) OR MIN(db_verOldBuild) <> MIN(db_verBuild)) AND MAX(db_status) <> 0 THEN GETDATE() ELSE MAX(stop_time) END, Run_Time = CASE WHEN (MIN(db_verOldMajor) <> @NewVersion OR MIN(db_verOldBuild) <> @NewBuild OR MIN(db_verOldMajor) <> MIN(db_verMajor) OR MIN(db_verOldBuild) <> MIN(db_verBuild)) AND MAX(db_status) <> 0 THEN GETDATE()-(SELECT TOP 1 start_time FROM DB_Upgrade WHERE db_name = DBU.db_name and PRODID = 0) ELSE MAX(stop_time)-(SELECT TOP 1 start_time FROM DB_Upgrade WHERE db_name = DBU.db_name and PRODID = 0) END, Upgrading = CASE WHEN EXISTS (select top 1 * from DU000030 DU INNER JOIN SY01500 SY on DU.companyID = SY.CMPANYID WHERE DU.Status NOT IN (0,15) AND DU.errornum <> 0 AND SY.INTERID = DBU.db_name) THEN -1 WHEN MAX(db_status) NOT IN (0,15) AND NOT EXISTS (SELECT * FROM duLCK L WHERE L.INTERID = DBU.db_name) THEN -1 WHEN MAX(db_status) NOT IN (0,15) THEN 1 WHEN EXISTS (SELECT * FROM duLCK L WHERE L.INTERID = DBU.db_name) THEN 2 ELSE 0 END, Status = db_status FROM DB_Upgrade DBU WHERE ( EXISTS( select * from DB_Upgrade where db_verMajor = @NewVersion and db_verBuild = @NewBuild AND PRODID = 0 AND db_name <> 'DYNAMICS' and db_name = DBU.db_name ) ) AND PRODID = 0 GROUP BY db_name, db_status UNION SELECT Completed_Company = RTRIM(db_name), Started_At = NULL, Ended_At = NULL, Run_Time = 0, Upgrading = 2, Status = db_status FROM DB_Upgrade DBU WHERE EXISTS ( select * from duLCK where DBU.db_name = duLCK.INTERID ) AND PRODID = 0 AND db_status = 0 GROUP BY db_name, db_status ) a SELECT Status = CASE Upgrading WHEN 2 THEN 'Pending' WHEN -1 THEN 'Failed' WHEN 1 THEN 'Upgrading' ELSE 'Completed' END, Company = CL.Completed_Company, [Last Step Completed] = CASE Status WHEN 0 THEN '' WHEN 1 THEN 'Step 1/59: Upgrade started' WHEN 2 THEN 'Step 2/59: Defaults loaded' WHEN 3 THEN 'Step 3/59: Tables created' WHEN 4 THEN 'Step 4/59: Indexes created' WHEN 5 THEN 'Step 5/59: Views created' WHEN 6 THEN 'Step 6/59: Dexterity procs created' WHEN 7 THEN 'Step 7/59: Changed Dexterity procs dropped' WHEN 8 THEN 'Step 8/59: Changed application procs dropped' WHEN 9 THEN 'Step 9/59: Changed indexes dropped' WHEN 10 THEN 'Step 10/59: Changed views dropped' WHEN 11 THEN 'Step 11/59: Changed triggers dropped' WHEN 12 THEN 'Step 12/59: Changed rules dropped' WHEN 13 THEN 'Step 13/59: Changed tables dropped' WHEN 14 THEN 'Step 14/59: SQL code updates ran' WHEN 15 THEN 'Step 15/59: New tables added' WHEN 16 THEN 'Step 16/59: Loading table stored procedures' WHEN 17 THEN 'Step 17/59: Loading required data' WHEN 21 THEN 'Step 21/59: Existing data conversion process started' WHEN 23 THEN 'Step 23/59: Existing data conversion process checkpoint' WHEN 30 THEN 'Step 30/59: Existing data conversion process completed' WHEN 41 THEN 'Step 41/59: New views added' WHEN 42 THEN 'Step 42/59: New triggers added' WHEN 43 THEN 'Step 43/59: Rules created' WHEN 44 THEN 'Step 44/59: Stubs created' WHEN 45 THEN 'Step 45/59: Misc stored procs created' WHEN 46 THEN 'Step 46/59: FRx data created' WHEN 47 THEN 'Step 47/59: Permissions script ran' WHEN 48 THEN 'Step 48/59: Table defaults bound' WHEN 49 THEN 'Step 49/59: Procs recompiled' WHEN 53 THEN 'Step 53/59: Functions loaded' WHEN 54 THEN 'Step 54/59: Application stored procs created, running misc scripts now' ELSE 'Step ' + CAST(Status as CHAR(2)) + '/59' END, Pending = CASE WHEN Upgrading = 1 THEN (select COUNT(*) FROM duLCK WHERE NOT EXISTS (SELECT * FROM #Completed_List AS c INNER JOIN duLCK as l ON c.Completed_Company = l.INTERID WHERE upgrading = 1 and INTERID = duLCK.INTERID) ) ELSE NULL END, [Not Upgraded] = CASE WHEN Upgrading = 1 THEN (select COUNT(*) from DB_Upgrade WHERE (db_verMajor <> @NewVersion OR db_verBuild <> @NewBuild) AND PRODID = 0 and db_name <> 'DYNAMICS') ELSE NULL END, Upgraded = CASE WHEN Upgrading = 1 THEN (select COUNT(*) from DB_Upgrade WHERE (db_verMajor = @NewVersion AND db_verBuild = @NewBuild AND db_verOldMajor = db_verMajor AND db_verOldBuild = db_verBuild) and PRODID = 0 and db_name <> 'DYNAMICS') ELSE NULL END, [Avg Time Per DB] = CASE WHEN Upgrading = 1 THEN CONVERT(varchar(4),DATEPART(DAY,(SELECT CAST(AVG(CAST(Run_Time as FLOAT)) as DATETIME) FROM #Completed_List WHERE Upgrading = 0))-1) + 'd ' + CONVERT(varchar(4),DATEPART(HOUR,(SELECT CAST(AVG(CAST(Run_Time as FLOAT)) as DATETIME) FROM #Completed_List WHERE Upgrading = 0))) + 'h ' + CONVERT(varchar(4),DATEPART(MINUTE,(SELECT CAST(AVG(CAST(Run_Time as FLOAT)) as DATETIME) FROM #Completed_List WHERE Upgrading = 0))) + 'm ' + CONVERT(varchar(4),DATEPART(SECOND,(SELECT CAST(AVG(CAST(Run_Time as FLOAT)) as DATETIME) FROM #Completed_List WHERE Upgrading = 0))) + 's ' ELSE '' END, [Est. Remaining Time] = CASE WHEN Upgrading = 1 THEN CONVERT(varchar(4),DATEPART(DAY,(SELECT CAST(AVG(CAST(Run_Time as FLOAT)) * (select COUNT(*) from DB_Upgrade WHERE (db_verMajor <> @NewVersion OR db_verBuild <> @NewBuild) AND PRODID = 0 and db_name <> 'DYNAMICS') as DATETIME) FROM #Completed_List WHERE Upgrading = 0) + ( (SELECT CAST(AVG(CAST(Run_Time as FLOAT)) as DATETIME) FROM #Completed_List WHERE Upgrading = 0) - (SELECT TOP 1 Run_Time FROM #Completed_List WHERE Upgrading = 1) ))-1) + 'd ' + CONVERT(varchar(4),DATEPART(HOUR,(SELECT CAST(AVG(CAST(Run_Time as FLOAT)) * (select COUNT(*) from DB_Upgrade WHERE (db_verMajor <> @NewVersion OR db_verBuild <> @NewBuild) AND PRODID = 0 and db_name <> 'DYNAMICS') as DATETIME) FROM #Completed_List WHERE Upgrading = 0) + ( (SELECT CAST(AVG(CAST(Run_Time as FLOAT)) as DATETIME) FROM #Completed_List WHERE Upgrading = 0) - (SELECT TOP 1 Run_Time FROM #Completed_List WHERE Upgrading = 1) ))) + 'h ' + CONVERT(varchar(4),DATEPART(MINUTE,(SELECT CAST(AVG(CAST(Run_Time as FLOAT)) * (select COUNT(*) from DB_Upgrade WHERE (db_verMajor <> @NewVersion OR db_verBuild <> @NewBuild) AND PRODID = 0 and db_name <> 'DYNAMICS') as DATETIME) FROM #Completed_List WHERE Upgrading = 0) + ( (SELECT CAST(AVG(CAST(Run_Time as FLOAT)) as DATETIME) FROM #Completed_List WHERE Upgrading = 0) - (SELECT TOP 1 Run_Time FROM #Completed_List WHERE Upgrading = 1) ))) + 'm ' + CONVERT(varchar(4),DATEPART(SECOND,(SELECT CAST(AVG(CAST(Run_Time as FLOAT)) * (select COUNT(*) from DB_Upgrade WHERE (db_verMajor <> @NewVersion OR db_verBuild <> @NewBuild) AND PRODID = 0 and db_name <> 'DYNAMICS') as DATETIME) FROM #Completed_List WHERE Upgrading = 0) + ( (SELECT CAST(AVG(CAST(Run_Time as FLOAT)) as DATETIME) FROM #Completed_List WHERE Upgrading = 0) - (SELECT TOP 1 Run_Time FROM #Completed_List WHERE Upgrading = 1) ))) + 's ' ELSE '' END, [Estimated End Time] = CASE WHEN Upgrading = 1 THEN CONVERT(varchar(20), GETDATE() + (SELECT CAST(AVG(CAST(Run_Time as FLOAT)) * (select COUNT(*) from DB_Upgrade WHERE (db_verMajor <> @NewVersion OR db_verBuild <> @NewBuild) AND PRODID = 0 and db_name <> 'DYNAMICS') as DATETIME) FROM #Completed_List WHERE Upgrading = 0) + ( (SELECT CAST(AVG(CAST(Run_Time as FLOAT)) as DATETIME) FROM #Completed_List WHERE Upgrading = 0) - (SELECT TOP 1 Run_Time FROM #Completed_List WHERE Upgrading = 1) ) ) ELSE '' END , [Elapsed Time] = CASE WHEN Upgrading = 1 THEN CONVERT(varchar(4),DATEPART(DAY,(SELECT CAST(SUM(CAST(Run_Time as FLOAT)) as DATETIME) FROM #Completed_List))-1) + 'd ' + CONVERT(varchar(4),DATEPART(HOUR,(SELECT CAST(SUM(CAST(Run_Time as FLOAT)) as DATETIME) FROM #Completed_List))) + 'h ' + CONVERT(varchar(4),DATEPART(MINUTE,(SELECT CAST(SUM(CAST(Run_Time as FLOAT)) as DATETIME) FROM #Completed_List))) + 'm ' + CONVERT(varchar(4),DATEPART(SECOND,(SELECT CAST(SUM(CAST(Run_Time as FLOAT)) as DATETIME) FROM #Completed_List))) + 's ' ELSE '' END FROM #Completed_List CL WHERE Upgrading <> 0 ORDER BY Status DESC, Company SELECT [Completed Company] = CASE WHEN Upgrading = 1 THEN Completed_Company + ' - Upgrading' WHEN Upgrading = -1 THEN Completed_Company + ' - Failed' ELSE Completed_Company END, [Completed Company Name] = RTRIM(CMPNYNAM), [Started At] = Started_At, [Ended At] = CASE WHEN Upgrading = -1 THEN Started_At ELSE Ended_At END, [Run Time] = CASE WHEN Upgrading = -1 THEN '0h 0m 0s' ELSE CONVERT(varchar(4),DATEPART(DAY,(Run_Time))-1) + 'd ' + CONVERT(varchar(4),DATEPART(HOUR,(Run_Time))) + 'h ' + CONVERT(varchar(4),DATEPART(MINUTE,(Run_Time))) + 'm ' + CONVERT(varchar(4),DATEPART(SECOND,(Run_Time))) + 's ' END FROM #Completed_List LEFT JOIN SY01500 ON #Completed_List.Completed_Company = SY01500.INTERID WHERE Upgrading <> 2 ORDER BY Upgrading DESC, [Ended At] DESC IF object_id('tempdb..#Completed_List') IS NOT NULL BEGIN DROP TABLE #Completed_List END
Labels:
Dynamics GP,
Progress,
Script,
SQL,
Upgrade
Friday, April 10, 2015
Beginning Balances not Showing in Management Reporter
We ran into an interesting issue where the numbers in Management Reporter did not match what was in Dynamics GP. We did the standard first step of re-creating the data mart and integration, but the numbers were still off.
Upon further investigation, the beginning balances were missing from the report. We looked in GP, and the trial balance looked right, but the MR numbers were still off.
Then we noticed that the Source Document for the beginning balances was not the standard "BBF"; it was "BF". It appeared that something had happened to GP during the year end close, so they created a journal entry to replace it then altered it in SQL to change the transaction date.
We had to update the Source Document in SQL and gave it an Original Transaction Source of "CLOSE". After re-creating the data mart, all was well in the world.
Upon further investigation, the beginning balances were missing from the report. We looked in GP, and the trial balance looked right, but the MR numbers were still off.
Then we noticed that the Source Document for the beginning balances was not the standard "BBF"; it was "BF". It appeared that something had happened to GP during the year end close, so they created a journal entry to replace it then altered it in SQL to change the transaction date.
We had to update the Source Document in SQL and gave it an Original Transaction Source of "CLOSE". After re-creating the data mart, all was well in the world.
Thursday, April 2, 2015
Time Log Excel Spreadsheet
As a consultant, I need to keep track of my day to make sure our company bills our customers for the appropriate hours I spend. If I'm working on one customer all day, it is pretty easy to enter my time into our billing system at the end of the day. On the other hand, when I'm working on several customers throughout the day and being interrupted by other customers and other consultants via meetings, e-mails, and phone calls, I need a spreadsheet where I can track every minute of the day - and is easy to see what I worked on for each external or internal customer when I'm entering my time into the billing system.
A colleague of mine had created the basic format, but it was very static. Always trying to improve and streamline, I changed it into a dynamic interface. Plus, I really wanted it to be easy to see all the work I did throughout the day for one particular customer and project.
I have been trying to ween myself off VBA in Excel whenever possible, so this spreadsheet contains no VBA macros - it is all Excel formulas and conditional formatting. The sheet is protected to keep data entry in the designated places, but there is no password if you want to poke around and see how it works.
Shoot me a comment if you find the spreadsheet useful.
Labels:
Conditional Formatting,
Excel
Friday, December 12, 2014
eConnect error - Name cannot begin with the 'x' character.
I just ran into a rather interesting error I'd never seen before in Integration Manager. This integration uses the eConnect destination adapter going into Purchase Orders.
The error we received was as follows:
eConnect error - Name cannot begin with the '6' character, hexidecimal value 0x36. Line 1, position 12559.
Integration Manager / eConnect creates the XML code automatically, so how would we even troubleshoot this?
I found a reference to an article on PartnerSource for saving the XML files IM/eConnect creates to a folder for troubleshooting, but the link was down and I couldn't find reference to it anywhere else on the internet (of course). See this page for a little more about the link (scroll down to the "Creating XML Data Files") section.
Looking at the data file and the error a few more times, I had a hunch there may be something wrong in the parsing of the import data so I looked through the text file for a '6' with a special character nearby. I found a 6 with the "less than" sign. Apparently Integration Manager 10 / eConnect couldn't handle this very well. I had the customer remove the "less than" sign, and all came in just fine.
Here is a screenshot from the import file (most of it is obscured for privacy reasons):
The error we received was as follows:
eConnect error - Name cannot begin with the '6' character, hexidecimal value 0x36. Line 1, position 12559.
Integration Manager / eConnect creates the XML code automatically, so how would we even troubleshoot this?
I found a reference to an article on PartnerSource for saving the XML files IM/eConnect creates to a folder for troubleshooting, but the link was down and I couldn't find reference to it anywhere else on the internet (of course). See this page for a little more about the link (scroll down to the "Creating XML Data Files") section.
Looking at the data file and the error a few more times, I had a hunch there may be something wrong in the parsing of the import data so I looked through the text file for a '6' with a special character nearby. I found a 6 with the "less than" sign. Apparently Integration Manager 10 / eConnect couldn't handle this very well. I had the customer remove the "less than" sign, and all came in just fine.
Here is a screenshot from the import file (most of it is obscured for privacy reasons):
Labels:
Dynamics GP,
eConnect,
Import,
Integration Manager
Monday, September 2, 2013
ASI_Explorer_Get_Field_List Script Terminated
I ran into this rather sketchy error on a customer system when trying to open the Sales Transaction SmartList:
Unhandled script exception:
Index 258 of array '[Not Found]' is out of range in script
'ASI_Explorer_Get_Field_List'. Script terminated
Generally an index out of range error means the array variable is dimentioned smaller than what the script is trying to pull out of it. For instance, the code is trying to access location 10 of an array with only 8 spots.
I went into the Tools >> Setup >> System >> SmartList Options window in GP and noticed that all the fields for the Sales Transaction SmartList were selected. I figured maybe the saved settings had gotten corrupted somehow and just needed to be re-saved. I clicked OK, and it gave me the error saying that I selected too many columns, and that I needed to reduce the number of display columns to less than 190.
I have not idea how they were all selected in the first place (or maybe the settings were somehow corrupt), but I just hit the Default button to reset the selection to just the default fields and saved. No more error.
Unhandled script exception:
Index 258 of array '[Not Found]' is out of range in script
'ASI_Explorer_Get_Field_List'. Script terminated
Generally an index out of range error means the array variable is dimentioned smaller than what the script is trying to pull out of it. For instance, the code is trying to access location 10 of an array with only 8 spots.
I went into the Tools >> Setup >> System >> SmartList Options window in GP and noticed that all the fields for the Sales Transaction SmartList were selected. I figured maybe the saved settings had gotten corrupted somehow and just needed to be re-saved. I clicked OK, and it gave me the error saying that I selected too many columns, and that I needed to reduce the number of display columns to less than 190.
I have not idea how they were all selected in the first place (or maybe the settings were somehow corrupt), but I just hit the Default button to reset the selection to just the default fields and saved. No more error.
Monday, June 10, 2013
Automatic Screen Capture
Description:
A utility to create automatic screenshots. Multiple monitors supported.
I created this program to help me go back through my day to see what all I worked on.
This is freeware. No reverse-engineering or anything like that. Use at your own risk.
One known issue - it does not handle the larger Windows 8 DPI settings very well. That will be the next thing I tackle whenever I get back around to working on the program.
WARNING:
This is not intended to capture someone's screen without their knowledge.
I will not change it to hide the system tray icon nor the process in Task Manager.
How To:
Settings Screen
| Prefix | File name prefix |
| Suffix | File name suffix, including timestamp; currently this is not editable |
| Folder | Folder in which to save the screenshots |
| Compression | Percent to which to compress the image files |
| A lower number creates smaller files; a higher number is higher quality | |
| 20 percent is the lowest suggested value that is still readable | |
| Capture | Amount of time between screenshots |
| Stop | Amount of time between reminders if the auto capture is stopped |
| Snooze | Snooze the capture and stop warnings |
| Set | Press to save and apply the settings |
| Start | Start or stop the auto capture |
| Minimize | Minimize the window to the system tray |
| Exit | Close the capture program |
| System Tray | |
| Double-click | Create a screenshot right now |
| Right-click | Settings | Open the settings window |
| Right-click | Start | Start or stop the auto capture |
| Right-click | Capture | Create a screenshow right now |
| Right-click | Snooze | Snooze for duration of selected time |
| Right-click | Exit | Close the program |
Notes:
If you stop the auto capture but do not fully exit the program, the settings window will pop up
after the interval specified in the Stop Reminder Interval. This is designed so you do not forget
to turn on the auto capture if you needed to stop it for a period of time but don't use snooze.
Version Info:
1.8
-------
Fixed a bug when manually entering a save folder
Added a capture button on the Settings window
Added statistics of Captures vs Missed timed screenshots
Added About window
1.7
-------
Added Snooze functionality to the system tray
Updated system tray icons to show the current status of the auto-capture; yellow if snoozed, red of stopped
Various code streamlining
1.6
-------
Added Snooze functionality; use from the settings window; this will pause captures and stop warnings
The Set botton will turn yellow when settings have changed but are not Set
The Snooze button will turn yellow while snoozing
Added warnings for un-Set changes before starting capture or exiting the program
Setting window format update
1.5
-------
Added the Stop Reminder Interval
Added Start/Stop to the system tray
Added Settings to the system tray
Changed the system tray double-click to be a manual screenshot
Updated the message box when closing the program from the settings screen
1.0
-------
Original version
Future enhancements
-------
Program icon
System Tray icon
Monitor selection
The download file is the executable itself - not an installation program.
Download from SkyDrive
Labels:
Automatic,
Free,
Screenshot
Thursday, April 11, 2013
GP User Activity with Status and IP
If you've ever needed to clear out old GP users, you know it can sometimes be difficult to figure out which ones are still connected and which ones are not. Yes, the ones that logged in two days ago may seem the obvious choices to kick out, but that's not always the case. We've seen users leave GP open for days on end to not lose their seat and their SQL session is hot, and we've seen users open GP in the morning but bombed out an hour later but didn't need it anymore so they didn't bother to log in to clear their seat.
Either way, this script below combines several GP and SQL system tables and views to give you a broad view of the status of your GP users. It will show whether users in User Activity are in fact still connected to GP, how long they've been logged into GP, when their last SQL activity occurred and how long ago it was, their computer's IP address, if they are working on batches, and what table they are currently working in.
I'm sure there is still some room for improvement, and I will be adding to it from time to time, so check back later for any updates.
Either way, this script below combines several GP and SQL system tables and views to give you a broad view of the status of your GP users. It will show whether users in User Activity are in fact still connected to GP, how long they've been logged into GP, when their last SQL activity occurred and how long ago it was, their computer's IP address, if they are working on batches, and what table they are currently working in.
I'm sure there is still some room for improvement, and I will be adding to it from time to time, so check back later for any updates.
USE DYNAMICS SELECT Activity.USERID UserID, Users.USERNAME Username, Activity.CMPNYNAM Company, CASE WHEN AbandonedSessions.SQLSESID IS NULL THEN 'Connected' ELSE 'Removable' END Status, CONVERT(varchar(20),ISNULL(ConnectedSessions.last_login,Activity.LOGINDAT + Activity.LOGINTIM)) LoggedInAt, ISNULL(CONVERT(varchar(20),ConnectedSessions.last_batch),'') LastGPUsage, CASE WHEN GETDATE()-(ISNULL(ConnectedSessions.last_login,Activity.LOGINDAT + Activity.LOGINTIM)) < 0 THEN '0d 0h 0m 0s' ELSE CONVERT(varchar(10),DAY(GETDATE()-(ISNULL(ConnectedSessions.last_login,Activity.LOGINDAT + Activity.LOGINTIM)))-1) + 'd ' + CONVERT(varchar(10),DATEPART(HOUR,GETDATE()-(ISNULL(ConnectedSessions.last_login,Activity.LOGINDAT + Activity.LOGINTIM)))) + 'h ' + CONVERT(varchar(10),DATEPART(MINUTE,GETDATE()-(ISNULL(ConnectedSessions.last_login,Activity.LOGINDAT + Activity.LOGINTIM)))) + 'm ' + CONVERT(varchar(10),DATEPART(SECOND,GETDATE()-(ISNULL(ConnectedSessions.last_login,Activity.LOGINDAT + Activity.LOGINTIM)))) + 's ' END TimeSinceLogin, CASE WHEN ConnectedSessions.last_batch IS NULL THEN '' WHEN GETDATE()-ConnectedSessions.last_batch < 0 THEN '0d 0h 0m 0s' ELSE CONVERT(varchar(10),DAY(GETDATE()-ConnectedSessions.last_batch)- 1) + 'd ' + CONVERT(varchar(10),DATEPART(HOUR,GETDATE()-ConnectedSessions.last_batch)) + 'h ' + CONVERT(varchar(10),DATEPART(MINUTE,GETDATE()-ConnectedSessions.last_batch)) + 'm ' + CONVERT(varchar(10),DATEPART(SECOND,GETDATE()-ConnectedSessions.last_batch)) + 's ' END GPIdleTime, ISNULL(lock.table_path_name,'') OpenTable, ISNULL(batch.BatchCount,0) BatchesInProgress, Activity.SQLSESID SessionID, ISNULL(CONVERT(varchar(10),ConnectedSessions.SPID),'') SPID, ISNULL(ConnectedSessions.client_net_address,'') IPAddress FROM DYNAMICS..ACTIVITY Activity INNER JOIN DYNAMICS..SY01400 Users ON Activity.USERID = Users.USERID LEFT JOIN ( SELECT * FROM DYNAMICS..Activity WHERE SQLSESID NOT IN ( SELECT SQLSESID FROM DYNAMICS..Activity A INNER JOIN tempdb..DEX_SESSION S ON A.SQLSESID = S.session_id INNER JOIN master..sysprocesses P on S.sqlsvr_spid = P.spid AND A.USERID = P.loginame ) AND NOT EXISTS (SELECT spid, c.CMPNYNAM DB, loginame,* FROM master..sysprocesses p inner join master..sysdatabases d on p.dbid = d.dbid inner join DYNAMICS..SY01500 c on d.name = RTRIM(c.INTERID) where c.CMPNYNAM = Activity.CMPNYNAM and p.loginame = Activity.USERID and p.program_name = '' ) ) AbandonedSessions ON Activity.SQLSESID = AbandonedSessions.SQLSESID AND Activity.USERID = AbandonedSessions.USERID LEFT JOIN ( SELECT A.SQLSESID, P.spid, P.last_batch, ec.client_net_address, CASE WHEN P.login_time < A.LOGINDAT + A.LOGINTIM THEN p.login_time ELSE A.LOGINDAT + A.LOGINTIM END last_login FROM DYNAMICS..Activity A INNER JOIN tempdb..DEX_SESSION S ON A.SQLSESID = S.session_id INNER JOIN master..sysprocesses P ON S.sqlsvr_spid = P.spid AND A.USERID = P.loginame INNER JOIN sys.dm_exec_connections ec ON S.sqlsvr_spid = ec.session_id ) ConnectedSessions ON Activity.SQLSESID = ConnectedSessions.SQLSESID LEFT JOIN ( SELECT session_id, max(table_path_name) table_path_name FROM tempdb..DEX_LOCK GROUP BY session_id ) lock ON Activity.SQLSESID = lock.session_id LEFT JOIN ( SELECT USERID, CMPNYNAM, COUNT(*) BatchCount FROM Dynamics..SY00800 GROUP BY USERID, CMPNYNAM ) batch ON Activity.USERID = batch.USERID and Activity.CMPNYNAM = batch.CMPNYNAM ORDER BY Activity.LOGINDAT, Activity.LOGINTIM
Labels:
Dynamics GP,
GP,
Script,
SQL,
User Activity
Thursday, April 4, 2013
Check Disk Space script
Part of normal maintenance of a Dynamics GP SQL server is to make sure there is enough disk space for your data as it grows. Similarly, you need to make sure your data files aren't growing more than they should.
This script draws from several system tables to show the recovery model, the last backup of the data or log file, the size of the file, the growth of the file the next time it runs out of room, the drive on which the file is stored, and the free space of the drive.
I included the Recovery Model and LastSQLBackup columns to show the situation where FULL recovery is used, but no Transaction Log backups are taking place. This situation causes the Transaction Log to grow unnecessarily until it fills the hard drive. If you do not back up the Transaction Log, having FULL recovery is both useless and dangerous to your data at the same time; dangerous because it can bottom out your hard drive while transactions are being posted, and useless because the log file hasn't been backed up to be able to use in a restore which is the whole point of having it in the first place.
-- Shows database file space usage and free disk space USE [master] IF EXISTS (SELECT * FROM sys.tables WHERE name='#cbs_drivespace') DROP TABLE #cbs_drivespace IF EXISTS (SELECT * FROM sys.tables WHERE name='##cbs_db_sizes') DROP TABLE ##cbs_db_sizes CREATE TABLE #cbs_drivespace ( Drive varchar(10), MB_Free numeric(19,2) ) CREATE TABLE ##cbs_db_sizes ( dbname varchar(100), filetype varchar(4), size_in_gb numeric(19,2), growth_in_percent numeric(19,2), growth_in_gb numeric(19,2) ) DECLARE @SQL varchar(4000) declare @DatabaseId varchar(255) INSERT INTO #cbs_drivespace(Drive, MB_Free) EXEC master.dbo.xp_fixeddrives declare DatabaseLoop cursor for select name from master..sysdatabases where name in (select INTERID from DYNAMICS..SY01500 union select 'DYNAMICS') or name in ('master','msdb','tempdb') open DatabaseLoop fetch next from DatabaseLoop into @DatabaseId while (@@fetch_status <> -1) begin /*Inner Loop for each Database*/ SET @SQL = 'INSERT INTO ##cbs_db_sizes ' + 'SELECT ''' + @DatabaseId + ''' AS dbname, ' + 'CASE WHEN RIGHT(RTRIM(filename),3) = ''mdf'' THEN ''Data'' ELSE ''Log'' END AS filetype, ' + 'CONVERT(numeric(19,2),size * 8 / 1024. / 1024) AS size_in_gb, ' + 'CONVERT(numeric(19,2),CASE WHEN status & 0x100000 > 0 THEN growth ELSE (growth * 100.) / (size * 1.) END) AS growth_in_percent, ' + 'CONVERT(numeric(19,2),CASE WHEN status & 0x100000 = 0 THEN growth * 8 / 1024. / 1024 ELSE size * (growth / 100.) * 8 / 1024 / 1024 END) AS growth_in_gb ' + 'FROM ' + @DatabaseId + '..sysfiles' EXEC (@SQL) fetch next from DatabaseLoop into @DatabaseId end close DatabaseLoop deallocate DatabaseLoop SELECT db.name as DBName, db.dbid as DBID, DatabasePropertyEX(db.name, 'Recovery') as RecoveryModel, s.filetype as FileType, CASE WHEN s.filetype = 'Data' THEN ISNULL(CONVERT(varchar(15),bu.LastBU,101),'Never') WHEN s.filetype = 'Log' AND DatabasePropertyEX(db.name, 'Recovery') = 'SIMPLE' THEN 'N/A' ELSE ISNULL(CONVERT(varchar(15),bu.LastBU,101),'Never') END LastSQLBackup, s.size_in_gb as SizeInGB, s.growth_in_gb as GrowthInGB, s.growth_in_percent as GrowthInPercent, ds.Drive as DriveLetter, CONVERT(numeric(19,2),ds.MB_Free / 1024) DriveGBFree FROM sysdatabases db INNER JOIN ##cbs_db_sizes s ON db.name = s.dbname INNER JOIN #cbs_drivespace ds ON LEFT(db.filename,1) = ds.Drive LEFT JOIN ( SELECT a.Name as dbname, COALESCE(Convert(varchar(100), MAX(b.backup_finish_date), 101),'Backup Not Taken') as LastBU, b.type as BUType, CASE WHEN b.type = 'D' THEN 'Data' WHEN b.type = 'L' THEN 'Log' END as BUFileMatch FROM sysdatabases a LEFT OUTER JOIN msdb.dbo.backupset b ON b.database_name = a.name WHERE b.type IN ('D','L') GROUP BY a.Name, b.type ) bu ON s.dbname = bu.dbname AND s.filetype = bu.BUFileMatch ORDER BY DBName,FileType DROP TABLE #cbs_drivespace DROP TABLE ##cbs_db_sizes
Wednesday, April 3, 2013
Copy Live to Test company - version 4
I've updated my script since my original post back in 2011 that is used to refresh a GP test company with live data.
This tried and tested script will perform the following:
Version 4 changes:
This tried and tested script will perform the following:
- Back up the current test database (optional; on by default)
- Back up the live database (optional; on by default)
- Restore the live backup (or, optionally, any other SQL backup)
- Run the CreateTestCompany (Microsoft) script
- Set the output settings to print to screen instead of a printer (optional; on by default)
- Change the Recovery Mode to Simple, and shrink the log file
DECLARE @SourceDatabase varchar(10), @TESTDatabase varchar(10), @DatabaseFolder varchar(1000), @LogFolder varchar(1000), @BackupFolder varchar(1000), @BackupFilename varchar(100), @TESTBackupFilename varchar(100), @RestoreFile varchar(100), @RestoreToDataFolder varchar(100), @RestoreToLogFolder varchar(100), @UseRestoreFile smallint, @UseRestoreToFolders smallint, @CompressionAllowed smallint, @Compress smallint, @BackupTESTFirst smallint, @LogicalFilenameDB varchar(100), @LogicalFilenameLog varchar(100), @SetPrintToScreen smallint, @SQL varchar(max) ----------------------------------------------------------------------- -- Set up all the information here for the live and test database names ----------------------------------------------------------------------- SET @SourceDatabase = 'TWO' USE [TWO] -- enter the Source Database between the braces SET @TESTDatabase = 'TEST' SET @BackupFolder = 'F:\DB Backups\' --end with a backslash (\) -- Folder where you want to save the backup file SET @Compress = 1 -- 0 = Do not compress backups; 1 = Compress backups -- 2008 and forward; SQL Express and some Standard editions do not allow compression SET @BackupTESTFirst = 1 -- 0 = No; 1 = Yes -- Backup the TEST database before restoring -- You should do this the first time you restore per day SET @UseRestoreFile = 0 -- 0 = Create a backup and restore it -- 1 = Use the below filename to restore from instead of creating new backup -- Use this when you just want to reload a backup you already created SET @RestoreFile = 'TWO_20130403.bak' -- File to restore if you have already created a backup of the live company SET @UseRestoreToFolders = 1 -- 0 = Restore to the same folder as the live database; -- 1 = Restore to the folders specified below SET @RestoreToDataFolder = 'G:\SQL Data TEST\' --end with a backslash (\) -- Folder where you want to restore the .mdf (Data) file TO SET @RestoreToLogFolder = 'H:\SQL Log TEST\' --end with a backslash (\) -- Folder where you want to restore the .ldf (Log) file TO SET @SetPrintToScreen = 1 -- 0 = No; 1 = Yes -- Change the posting output to the screen instead of the printer ----------------------------------------------------------------------- ----------------------------------------------------------------------- ----------------------------------------------------------------------- SELECT @CompressionAllowed = CONVERT(smallint,ISNULL((SELECT value FROM sys.configurations WHERE name = 'backup compression default'),-1)) SELECT @LogicalFilenameDB = (rtrim(name)) FROM dbo.sysfiles WHERE groupid = 1 SELECT @LogicalFilenameLog = (rtrim(name)) FROM dbo.sysfiles WHERE groupid = 0 IF @UseRestoreToFolders = 1 BEGIN SET @DatabaseFolder = @RestoreToDataFolder SET @LogFolder = @RestoreToLogFolder print 'Using specified data folder ' + @DatabaseFolder + ' and log folder ' + @LogFolder END ELSE BEGIN SELECT TOP 1 @DatabaseFolder = left(filename,len(filename)-charindex('\',reverse(filename))+1) FROM dbo.sysfiles WHERE groupid = 1 SELECT TOP 1 @LogFolder = left(filename,len(filename)-charindex('\',reverse(filename))+1) FROM dbo.sysfiles WHERE groupid = 0 print 'Using live database''s data folder ' + @DatabaseFolder + ' and log folder ' + @LogFolder END print 'Compression: ' + CASE WHEN @Compress = 1 AND @CompressionAllowed = -1 THEN 'NOT ALLOWED' WHEN @Compress = 1 THEN 'ON' ELSE 'OFF' END print @LogicalFilenameDB print @LogicalFilenameLog print @DatabaseFolder SET @SQL = '' IF @UseRestoreFile = 0 BEGIN SET @BackupFilename = @BackupFolder + @SourceDatabase + '_' + convert(varchar(4),year(GETDATE())) + right('00' + convert(varchar(2),month(GETDATE())),2) + right('00' + convert(varchar(2),day(GETDATE())),2) + '_' + replace(CONVERT(VARCHAR(8),GETDATE(),108),':','') + '_for_' + @TESTDatabase + '.bak' END ELSE BEGIN SET @BackupFilename = @BackupFolder + @RestoreFile END print '.' print 'Backup Filename: ' + @BackupFilename print '.' SET @TESTBackupFilename = @BackupFolder + @TESTDatabase + '_' + convert(varchar(4),year(GETDATE())) + right('00' + convert(varchar(2),month(GETDATE())),2) + right('00' + convert(varchar(2),day(GETDATE())),2) + '_' + replace(CONVERT(VARCHAR(8),GETDATE(),108),':','') + '_pre_LIVE_restore.bak' -- check to see if the TEST database is in use first IF EXISTS(SELECT spid,loginame=rtrim(loginame),hostname,program_name,login_time,dbname = (CASE WHEN dbid = 0 THEN NULL WHEN dbid <> 0 THEN db_name(dbid) END) FROM master.dbo.sysprocesses WHERE CASE WHEN dbid = 0 THEN NULL WHEN dbid <> 0 THEN db_name(dbid) END = @TESTDatabase) BEGIN PRINT 'The database is in use' SELECT spid,loginame=rtrim(loginame),hostname,program_name,login_time,dbname = (CASE WHEN dbid = 0 THEN NULL WHEN dbid <> 0 THEN db_name(dbid) END) FROM master.dbo.sysprocesses WHERE CASE WHEN dbid = 0 THEN NULL WHEN dbid <> 0 THEN db_name(dbid) END = @TESTDatabase END ELSE BEGIN IF @UseRestoreFile = 0 BEGIN -- Back up the LIVE database SET @SQL = '' + 'PRINT ''Backing up Source database (' + @SourceDatabase + ')''; ' + 'BACKUP DATABASE [' + @SourceDatabase + '] TO DISK ' + '= N''' + @BackupFilename + ''' ' + 'WITH COPY_ONLY, NOFORMAT, NOINIT, NAME ' + '= N''' + @SourceDatabase + '-Full Database Backup'', SKIP, NOREWIND, NOUNLOAD, STATS = 10' IF @Compress = 1 AND @CompressionAllowed > -1 SET @SQL = @SQL + ', COMPRESSION' EXEC (@SQL) END -- Back up the TEST database IF @BackupTESTFirst = 1 BEGIN SET @SQL = '' + 'PRINT ''Backing up Destination database (' + @TESTDatabase + ')''; ' + 'BACKUP DATABASE [' + @TESTDatabase + '] TO DISK ' + '= N''' + @TESTBackupFilename + ''' ' + 'WITH COPY_ONLY, NOFORMAT, NOINIT, NAME ' + '= N''' + @TESTDatabase + '-Full Database Backup'', SKIP, NOREWIND, NOUNLOAD, STATS = 10' IF @Compress = 1 AND @CompressionAllowed > -1 SET @SQL = @SQL + ', COMPRESSION' EXEC (@SQL) END -- Restore to the TEST database SET @SQL = '' + 'PRINT ''Restoring to Destination database (' + @TESTDatabase + ')''; ' + 'RESTORE DATABASE [' + @TESTDatabase + '] FROM DISK ' + '= N''' + @BackupFilename + ''' ' + 'WITH FILE = 1, ' + 'MOVE N''' + @LogicalFilenameDB + ''' TO ' + 'N''' + @DatabaseFolder + 'GPS' + @TESTDatabase + 'Dat.mdf'', ' + 'MOVE N''' + @LogicalFilenameLog + ''' TO ' + 'N''' + @LogFolder + 'GPS' + @TESTDatabase + 'Log.ldf'', ' + 'NOUNLOAD, REPLACE, STATS = 10' EXEC (@SQL) SET @SQL = '' + 'PRINT ''Setting Recovery Model to Simple''; ' + 'ALTER DATABASE [' + @TESTDatabase + '] SET RECOVERY SIMPLE WITH NO_WAIT' EXEC (@SQL) SET @SQL = '' + 'PRINT ''Shrinking Log File'' ' + 'USE [' + @TESTDatabase + '] ' + 'DBCC SHRINKFILE (N''' + @LogicalFilenameLog + ''' , 0, TRUNCATEONLY)' EXEC (@SQL) IF @SetPrintToScreen = 1 BEGIN SET @SQL = '' + 'PRINT ''Setting output to print to screen instead of printer'' ' + 'USE [' + @TESTDatabase + '] ' + 'UPDATE SY02200 SET PRTOSCNT = 1, PRTOPRNT = 0' EXEC (@SQL) END -- Run the CreateTestCompany script from MS SET @SQL = '' + 'PRINT ''Running CreateTestCompany script on ' + @TESTDatabase + '''; ' + 'USE [' + @TESTDatabase + '] ' + 'if not exists(select 1 from tempdb.dbo.sysobjects where name = ''##updatedTables'') ' + ' create table [##updatedTables] ([tableName] char(100)) ' + 'truncate table ##updatedTables ' + 'declare @cStatement varchar(255) ' + 'declare G_cursor CURSOR for ' + 'select ' + 'case ' + 'when UPPER(a.COLUMN_NAME) in (''COMPANYID'',''CMPANYID'') ' + ' then ''update ''+a.TABLE_NAME+'' set ''+a.COLUMN_NAME+'' = ''+ cast(b.CMPANYID as char(3)) ' + 'else ' + '''update ''+a.TABLE_NAME+'' set ''+a.COLUMN_NAME+'' = ''''''+ db_name()+'''''''' ' + 'end ' + 'from INFORMATION_SCHEMA.COLUMNS a, DYNAMICS.dbo.SY01500 b, INFORMATION_SCHEMA.TABLES c ' + 'where UPPER(a.COLUMN_NAME) in (''COMPANYID'',''CMPANYID'',''INTERID'',''DB_NAME'',''DBNAME'', ''COMPANYCODE_I'') ' + 'and b.INTERID = db_name() and a.TABLE_NAME = c.TABLE_NAME and c.TABLE_CATALOG = db_name() and c.TABLE_TYPE = ''BASE TABLE''; ' + 'set nocount on; ' + 'OPEN G_cursor; ' + 'FETCH NEXT FROM G_cursor INTO @cStatement ' + 'WHILE (@@FETCH_STATUS <> -1) ' + 'begin ' + 'insert ##updatedTables select ' + 'substring(@cStatement,8,patindex(''%set%'',@cStatement)-9) ' + 'Exec (@cStatement) ' + 'FETCH NEXT FROM G_cursor INTO @cStatement ' + 'end ' + 'DEALLOCATE G_cursor ' + 'select [tableName] as ''Tables that were Updated'' from ##updatedTables ' EXEC (@SQL) PRINT 'Don''t forget to run GP SQL Maintenance on the ' + @TESTDatabase + ' database.' END
Version 4 changes:
- Specify the restore folder for the data file (.mdf)
- Specify the restore folder for the log file (.ldf)
- Backup compression (optional; on by default)
- Uses the "Copy Only" switch - so it does not mark the database as backed up - useful when using certain other backup software as the primary backup
- Messages window shows the auto-generated backup filename of the LIVE database for use in the optional restore feature below
- Restores a backup you already created (optional)
- Changes the posting output of the TEST company in GP to Screen instead of Printer (optional)
- Changes the Recovery Model to Simple and shrinks the log file of the TEST database
- Backs up the TEST database (optional)
- Backs up the LIVE database and restore to the TEST database
- Runs CreateTestCompany script from PartnerSource against the TEST database
Labels:
Dynamics GP,
GP,
Script,
SQL,
Test Company
Wednesday, March 21, 2012
Happy Birthday, SQL Style
There was a birthday in our office recently and it inspired me to send them a SQL statement that "I was getting weird results from" and if they could do me a favor and run it on their system to see what they get. I had them run it against the TWO database (if you are a GP admin, you'll get the subtle joke there when you run it). The one I sent wasn't quite this fancy, but I just couldn't leave it be with that I had so here you are.
Just FYI, it's meant to be obfuscated and a little over-complicated so it's a surprise when run by the birthday guy/girl. It's better if using Windows authentication or a user-specific account (as opposed to 'sa'). I'm sure the trained eye will see through it right away, but for those starting out it's an interesting example of what can be done in SQL.
Just FYI, it's meant to be obfuscated and a little over-complicated so it's a surprise when run by the birthday guy/girl. It's better if using Windows authentication or a user-specific account (as opposed to 'sa'). I'm sure the trained eye will see through it right away, but for those starting out it's an interesting example of what can be done in SQL.
WITH CTE_HB1 (a,b,c,d) AS ( SELECT TOP 1 MAX(a),MAX(b),MAX(c),MAX(d) FROM ( SELECT CHAR(72) + CHAR(65) + CHAR(80) + CHAR(80) + CHAR(89) + CHAR(32) a, 'AA20100' b,CASE DB_NAME() WHEN 'TWO' THEN DB_NAME() ELSE CHAR(84)+CHAR(79) END c,CHAR(89) + 'OU' + CHAR(33) + CHAR(33) d UNION ALL SELECT 'GL20000', CHAR(66) + CHAR(73) + CHAR(82) + CHAR(84) + CHAR(72) + CHAR(68) + CHAR(65) + CHAR(89),CHAR(66) + 'R', 'A' + 'TU' ) UPR00100 ), CTE_HB2 (e,f) AS ( SELECT CHAR(68) + CHAR(69) + CHAR(65) + CHAR(82),SUSER_SNAME() ) SELECT a.a ' 1 ', a.b ' 2 ', a.c ' 3 ', a.d ' 4 ' FROM CTE_HB1 a CROSS APPLY (SELECT 1 a UNION ALL SELECT 2) b UNION ALL SELECT a.a,a.b,b.e,b.f FROM CTE_HB1 a CROSS APPLY CTE_HB2 b UNION ALL SELECT a.* FROM CTE_HB1 a
Labels:
SQL Birthday
Thursday, November 10, 2011
How to See the Current Status of a Dynamics GP Upgrade or Service Pack
UPDATE: See updated version here.
I've referenced before that we have a customer with over 80 GP companies; they are the mother of many script inventions for me as I have no desire to manually do anything for 80 databases. Well, now they are at 90.
Needless to say, one of the many challenges with such a large number of companies is keeping track of where the database processing is during an upgrade or service pack. It would also be nice to know how long the thing is going to take.
Here is a handy little script I created to help keep track of this:
Edit 8/20/2014: Fixed a couple letter cases to work properly for Binary SQL sorting
Edit 10/15/2014: See updated script here
I've referenced before that we have a customer with over 80 GP companies; they are the mother of many script inventions for me as I have no desire to manually do anything for 80 databases. Well, now they are at 90.
Needless to say, one of the many challenges with such a large number of companies is keeping track of where the database processing is during an upgrade or service pack. It would also be nice to know how long the thing is going to take.
Here is a handy little script I created to help keep track of this:
Edit 8/20/2014: Fixed a couple letter cases to work properly for Binary SQL sorting
Edit 10/15/2014: See updated script here
DECLARE @NewVersion int DECLARE @NewBuild int SET @NewVersion = 11 -- Change this to the major version number you are upgrading TO SET @NewBuild = 1752 -- Change this to the build number you are upgrading TO IF object_id('tempdb..#Completed_List') IS NOT NULL BEGIN DROP TABLE #Completed_List END SELECT * INTO #Completed_List FROM ( SELECT Completed_Company = RTRIM(db_name), Started_At = (SELECT start_time FROM DB_Upgrade WHERE db_name = DBU.db_name and PRODID = 0), Ended_At = CASE WHEN (MIN(db_verOldMajor) <> @NewVersion OR MIN(db_verOldBuild) <> @NewBuild OR MIN(db_verOldMajor) <> MIN(db_verMajor) OR MIN(db_verOldBuild) <> MIN(db_verBuild)) AND MAX(db_status) <> 0 THEN GETDATE() ELSE MAX(stop_time) END, Run_Time = CASE WHEN (MIN(db_verOldMajor) <> @NewVersion OR MIN(db_verOldBuild) <> @NewBuild OR MIN(db_verOldMajor) <> MIN(db_verMajor) OR MIN(db_verOldBuild) <> MIN(db_verBuild)) AND MAX(db_status) <> 0 THEN GETDATE()-(SELECT start_time FROM DB_Upgrade WHERE db_name = DBU.db_name and PRODID = 0) ELSE MAX(stop_time)-(SELECT start_time FROM DB_Upgrade WHERE db_name = DBU.db_name and PRODID = 0) END, Upgrading = CASE WHEN MAX(db_status) <> 0 THEN 1 ELSE 0 END FROM DB_Upgrade DBU WHERE EXISTS( select * from DB_Upgrade where db_verMajor = @NewVersion and db_verBuild = @NewBuild AND PRODID = 0 AND db_name <> 'DYNAMICS' and db_name = DBU.db_name ) GROUP BY db_name ) a SELECT Currently_Upgrading = ISNULL((select TOP 1 db_name from DB_Upgrade where ((db_verMajor = @NewVersion AND db_verBuild = @NewBuild) AND (db_verOldMajor <> db_verMajor OR db_verOldBuild <> db_verBuild)) and PRODID = 0 and db_name <> 'DYNAMICS' order by start_time desc), (SELECT TOP 1 db_name FROM DB_Upgrade WHERE db_status <> 0)), Not_Upgraded = (select COUNT(*) from DB_Upgrade WHERE (db_verMajor <> @NewVersion OR db_verBuild <> @NewBuild) AND PRODID = 0 and db_name <> 'DYNAMICS'), Upgraded = (select COUNT(*) from DB_Upgrade WHERE (db_verMajor = @NewVersion AND db_verBuild = @NewBuild AND db_verOldMajor = db_verMajor AND db_verOldBuild = db_verBuild) and PRODID = 0 and db_name <> 'DYNAMICS'), Average_Time_Per_DB = CONVERT(varchar(4),DATEPART(HOUR,(SELECT CAST(AVG(CAST(Run_Time as FLOAT)) as DATETIME) FROM #Completed_List WHERE Upgrading = 0))) + 'h ' + CONVERT(varchar(4),DATEPART(MINUTE,(SELECT CAST(AVG(CAST(Run_Time as FLOAT)) as DATETIME) FROM #Completed_List WHERE Upgrading = 0))) + 'm ' + CONVERT(varchar(4),DATEPART(SECOND,(SELECT CAST(AVG(CAST(Run_Time as FLOAT)) as DATETIME) FROM #Completed_List WHERE Upgrading = 0))) + 's ' , Elapsed_Time = CONVERT(varchar(4),DATEPART(HOUR,(SELECT CAST(SUM(CAST(Run_Time as FLOAT)) as DATETIME) FROM #Completed_List))) + 'h ' + CONVERT(varchar(4),DATEPART(MINUTE,(SELECT CAST(SUM(CAST(Run_Time as FLOAT)) as DATETIME) FROM #Completed_List))) + 'm ' + CONVERT(varchar(4),DATEPART(SECOND,(SELECT CAST(SUM(CAST(Run_Time as FLOAT)) as DATETIME) FROM #Completed_List))) + 's ' , Estimated_Remaining_Time = CONVERT(varchar(4),DATEPART(HOUR,(SELECT CAST(AVG(CAST(Run_Time as FLOAT)) * (select COUNT(*) from DB_Upgrade WHERE (db_verMajor <> @NewVersion OR db_verBuild <> @NewBuild) AND PRODID = 0 and db_name <> 'DYNAMICS') as DATETIME) FROM #Completed_List WHERE Upgrading = 0) + ( (SELECT CAST(AVG(CAST(Run_Time as FLOAT)) as DATETIME) FROM #Completed_List WHERE Upgrading = 0) - (SELECT Run_Time FROM #Completed_List WHERE Upgrading = 1) ))) + 'h ' + CONVERT(varchar(4),DATEPART(MINUTE,(SELECT CAST(AVG(CAST(Run_Time as FLOAT)) * (select COUNT(*) from DB_Upgrade WHERE (db_verMajor <> @NewVersion OR db_verBuild <> @NewBuild) AND PRODID = 0 and db_name <> 'DYNAMICS') as DATETIME) FROM #Completed_List WHERE Upgrading = 0) + ( (SELECT CAST(AVG(CAST(Run_Time as FLOAT)) as DATETIME) FROM #Completed_List WHERE Upgrading = 0) - (SELECT Run_Time FROM #Completed_List WHERE Upgrading = 1) ))) + 'm ' + CONVERT(varchar(4),DATEPART(SECOND,(SELECT CAST(AVG(CAST(Run_Time as FLOAT)) * (select COUNT(*) from DB_Upgrade WHERE (db_verMajor <> @NewVersion OR db_verBuild <> @NewBuild) AND PRODID = 0 and db_name <> 'DYNAMICS') as DATETIME) FROM #Completed_List WHERE Upgrading = 0) + ( (SELECT CAST(AVG(CAST(Run_Time as FLOAT)) as DATETIME) FROM #Completed_List WHERE Upgrading = 0) - (SELECT Run_Time FROM #Completed_List WHERE Upgrading = 1) ))) + 's ' SELECT Completed_Company = CASE WHEN Upgrading = 1 THEN Completed_Company + ' - Upgrading' ELSE Completed_Company END, Started_At, Ended_At, Run_Time = CONVERT(varchar(4),DATEPART(HOUR,(Run_Time))) + 'h ' + CONVERT(varchar(4),DATEPART(MINUTE,(Run_Time))) + 'm ' + CONVERT(varchar(4),DATEPART(SECOND,(Run_Time))) + 's ' FROM #Completed_List ORDER BY Upgrading DESC, Ended_At DESC IF object_id('tempdb..#Completed_List') IS NOT NULL BEGIN DROP TABLE #Completed_List END
Labels:
Dynamics GP,
Progress,
Script,
Service Pack,
SQL,
Status,
Upgrade
Subscribe to:
Posts (Atom)




