Batchverwerking van bestanden met Windows functie ForFiles

Ik ben al langer op zoek naar een manier om bestanden in een batch te verwerken; in het bijzonder het verwijderen van bestanden die meer dan X dagen oud zijn. Tijdens mijn zoektocht kwam ik de Windows functie ForFiles tegen. Het verraste mij dat bij het schrijven van deze bijdrage blijkt dat deze functie als sinds Windows Vista beschikbaar is.

Hoe het werkt
ForFiles werkt met een aantal parameters, die…

  • Alle bestanden in een folder langsloopt
  • Ook in subfolders kan kijken
  • Windows bewerkingen (o.a. DELETE) op deze bestanden kan uitvoeren

Voorbeeld
ForFiles /S /P “[drive]:[Folder]” /D -10 /C “cmd /c del /F /Q @file”

Bovenstaand voorbeeld verwijdert alle bestanden ouder dan 10 dagen uit de betrokken folder en alle onderliggende subfolders.

Meer weten
Onderstaande bijdragen zijn in het Engels en hebben nog wat extra voorbeelden:

SSAS Analysis Server melding Multi-dimensional database is not using latest encryption schema.

Bij het uitrollen van een multi-dimensionale kubussolution krijgt u de melding An error has occurred, please contact your administrator \nErrors in the metadata manager. Multi-dimensional database [kubusdatabase] is not using latest encryption schema. Please create a backup file and restore DB from backup file with the option EnsureProperEncryption to upgrade to the latest encryption..

Dit is een nieuwe functionaliteit in SQL Server 2022. Eenmalig dient er bij deze melding een backup te worden gemaakt van de kubusdatabase en dient deze backup te worden terug gezet waarbij de optie ‘EnsureProperEncryption’ op ‘True’ staat. Is dat eenmaal gebeurt, dan kunnen toekomstige updates van deze kubussolution weer normaal worden uitgerold zonder dat de kubussolution hoeft te worden verwijderd.

Link: Microsoft pagina’s in het Engels die van toepassing zijn.

De LSAlert op de logship database server geeft onterecht een foutmelding!

Het volgende scenario doet zich op de SQL Server database server voor waar de logship database op staat:

  • De LSAlert job geeft aan dat de logship database niet is bijgewerkt en ‘out-of-sync’ is
  • De LSRestore job geeft een groen vinkje om aan te geven dat die job goed heeft gelopen
  • De logship database is bijgewerkt
  • Recente data uit de brondatabase is ook in de logship database zichtbaar en beschikbaar

Maar … de logship database staat op een SQL Server versie die lager is dan de brondatabase. Bijvoorbeeld de logship database draait op SQL Server versie 2016 en de brondatabase draait (al) op SQL Server versie 2022.

Dit kan tot problemen leiden, omdat de database structuur van systeem databases (zoals bijvoorbeeld msdb) waar SQL Server logging naar toe schrijft een andere structuur hebben (bijvoorbeeld nieuwe velden in systeemtabellen of velden die naar andere systeemtabellen zijn verplaatst). Het zou dan kunnen dat de LSRestore job dan gegevens probeert weg te schrijven die in de nieuwere versie van SQL Server niet meer van toepassing zijn of zijn verplaatst.

Valt dit dan nergens op? Tot nu toe heeft SQLTeam een foutmelding in de schijnbaar goed afgeronde LSRestore job gevonden. Namelijk de foutmelding:

*** Error: Could not log history/error message.(Microsoft.SqlServer.Management.LogShipping) ***
*** Error: Failed to convert parameter value from a SqlGuid to a String.(System.Data) ***
*** Error: Object must implement IConvertible.(mscorlib) ***

Het niet kunnen wegschrijven van log historie en foutmeldingen uit bovenstaande melding. Triggert de LSAlert job die van deze logging gebruik maakt om te kijken of een logship database is bijgewerkt. Hoewel de melding uit de LSAlert job dus inderdaad onterecht is, is dat in deze situatie goed te verklaren. Bovenstaande foutmelding doet zich voor wanneer de logship database op een lagere versie draait dan de brondatabase.

Onderstaande foutmelding doet zich voor wanneer de logship database op een hogere versie van SQL Server staat dan de brondatabase.

2024-07-23 03:25:00.87 *** Error: An error occurred restoring the database access mode.(Microsoft.SqlServer.Management.LogShipping) ***
2024-07-23 03:25:00.89 *** Error: Alter failed for Database '[Naam van de logship database]'. (Microsoft.SqlServer.Smo) ***
2024-07-23 03:25:00.89 *** Error: An exception occurred while executing a Transact-SQL statement or batch.(Microsoft.SqlServer.ConnectionInfo) ***
2024-07-23 03:25:00.89 *** Error: Database '[Naam van de logship database]' cannot be opened. It is in the middle of a restore.(.Net SqlClient Data Provider) ***
2024-07-23 03:25:00.92 *** Error: Could not apply log backup file '[Naam en locatie van de transactielog.trn]' to secondary database '[Naam van de logship database]'.(Microsoft.SqlServer.Management.LogShipping) ***
2024-07-23 03:25:00.92 *** Error: This backup cannot be restored using WITH STANDBY because a database upgrade is needed. Reissue the RESTORE without WITH STANDBY.
RESTORE LOG is terminating abnormally.(.Net SqlClient Data Provider) ***

Advies
Zorg ervoor dat de SQL versies van de brondatabase (primary) en de logship databases van die brondatabase(s) (secondary of secondaries) altijd gelijk aan elkaar is om dit soort situaties te voorkomen.

Opeens “Service Unavailable” op een relatief nieuwe Report Server(?)

Is dit bij u aan de hand…

  • U heeft net een nagelnieuwe Report Server opgeleverd gekregen?
  • U maakt verbinding met de Report Server via een internet browser?
  • Dat gaat een paar weken goed, totdat opeens bij het openen van de report server wél de folders worden getoond, maar bij het openen van elk rapport de melding “Service Unavailable” veschijnt?

De waarschijnlijke oorzaak is dat de evaluatie-versie van Report Server is geïnstalleerd. Dit is te controleren door in de folder C:\Program Files\Microsoft SQL Server Reporting Services\SSRS\LogFiles\ (of de folder waar bij u Report Server is geïnstalleerd) het logbestand ReportingServicesService_[datum/tijd].log te openen en te scannen op meldingen.

… En ja … Betrek altijd alle logs van SQL Server bij uw analyses. Ze zijn écht uw beste vrienden.

Foutmelding bij deployen van kubussolutions naar een Microsoft SQL Server Analysis Server

Enige tijd geleden was ik bezig met het deployen van kubussolutions naar een Microsoft SQL Server Analysis Server. Bij het deployen, verscheen de volgende melding An error has occurred, please contact your administrator \nInternal error: An unexpected error occurred (file ‘pcserialize.cpp’, line 1535, function ‘ASDatabase::Serialize’)

“An unexpected error”; typisch Microsoft waar je dus niets mee kunt. Na lang onderzoek bleek de oorzaak eigenlijk heel simpel: in het security tabblad van de server properties waren geen administrators opgenomen; zelfs geen BUILTIN\Administrators. Blijkbaar is het een goed idee om in dat tabblad in ieder geval één account te vermelden. Zo dus…

Na het toevoegen van een administrator in dit tabblad, rolden de kubussolutions wél goed uit.

SQL Server databases – informatie over de restore van een backup

Regelmatig krijg ik de vraag: “Weet jij wanneer de backup van [deze] en [deze] database is gemaakt en wanneer die is teruggezet?”. Het antwoord is ‘ja’… en met deze bijdrage weet u het nu ook. Draai op de SQL Server waar de teruggezette database staat onderstaande query:

SELECT 
   [rs].[destination_database_name], 
   [rs].[restore_date], 
   [bs].[backup_start_date], 
   [bs].[backup_finish_date], 
   [bs].[database_name] as [source_database_name], 
   [bmf].[physical_device_name] as [backup_file_used_for_restore]
FROM msdb..restorehistory rs
INNER JOIN msdb..backupset bs ON [rs].[backup_set_id] = [bs].[backup_set_id]
INNER JOIN msdb..backupmediafamily bmf ON [bs].[media_set_id] = [bmf].[media_set_id] 
ORDER BY [rs].[restore_date] DESC

Zo wordt de gevraagde informatie gevonden.

Met dank aan Thomas LaRock die deze informatie in het Engels in deze bijdrage heeft gedeeld.

Opstarten SQL Server onder ‘Local Service’ account; niet doen!

Bij de installatie van SQL Server wordt de SQL Service onder een zogenaamd local service account gestart. Heel af en toe valt het mij op dat het service account waaronder onderdelen van SQL Server worden gestart, niet naar een domein account wordt gewijzigd. Het is verstandig om de onderdelen van SQL Server onder aparte (!) domein accounts te laten starten; dus een apart domein account voor de database engine, een apart domein account voor de analysis server, één voor de SQL Agent, etc.

Waarom zo moeilijk als het ook makkelijk kan?
Het gebruik van een domein account zorgt ervoor dat op de onderdelen van SQL Server eenvoudiger wijzigingen kunnen worden gemaakt. Afgelopen week kwam ik tegen dat SSAS kubussolutions niet naar een analysis server konden worden uitgerold, omdat er geen gebruik van een domein account werd gemaakt. Bij gebruik van het ‘local service account’ weet het systeem niet of er voldoende rechten zijn bij o.a. het uitrollen van de kubussolutions vanaf een andere machine.

Ok… maar aparte domein accounts voor elk onderdeel van SQL Server?
Hoeft niet, maar het maakt de rechtenstructuur wél duidelijker. Een voorbeeld: om kubussen bij te werken onder het service account waaronder de analysis server wordt gestart, dient dat service account wél leesrechten te hebben op de brondatabase van de database engine; óók wanneer de database engine onder hetzelfde domein account wordt gestart. Het is dan overzichtelijker en duidelijker om de analysis server met een eigen service account te starten.

Kan het nóg scherper / beter?
Ja, door gebruik te maken van “(group) managed service accounts”. Het is wat meer werk, maar heeft als voordeel dat deze accounts uitsluitend kunnen worden gebruikt door de machines die hier rechten voor hebben gekregen. Daarnaast heeft dit account geen wachtwoord, waardoor het account ook niet voor andere doeleinden kan worden gebruikt / misbruikt. Met dank aan mijn collega voor deze mooie aanvulling.

Dus gebruik domein (group) managed service accounts bij het starten van onderdelen van SQL Server in een netwerk met Active Directory als basis.

** SQL Server database compatibility level? Wat is dat? **

Regelmatig komen we databases tegen die op de laatste versie van Microsoft SQL Server draaien en toch niet van de laatste technieken en inzichten gebruik kunnen maken. Met de verhuizing van een SQL Server database naar een nieuwe machine met de laatste SQL Server versie is het nog niet klaar! Dat geldt ook wanneer de SQL Server wordt bijgewerkt met de laatste versie van SQL Server. De betrokken database(s) moet(en) nog worden bijgewerkt!

Microsoft die zorgt ervoor dat een nieuwere versie van SQL Server niet direct impact heeft op de databases die op de SQL Server draaien. Elke database heeft op database niveau in het tabblad ‘Options’ de instelling ‘Compatibility Level’. Deze instelling zorgt ervoor dat de database zich gedraagt zoals die op de ‘oude’ versie van SQL Server is aangemaakt. Dit voorkomt dat de database opeens onder andere performance issues geeft of query plannen maakt, waar de database helemaal niet geschikt voor is.

Wanneer wordt de instelling “Compatibility Level” dan gewijzigd?
Na uitgebreide tests! De best-practice is om een kopie van de database op een testmachine te plaatsen en eerst daar deze instelling naar de hoogste versie te brengen om vervolgens alle relevante query’s en andere processen op de database te testen. Vervolgens kunnen op deze database dan de nodige wijzigingen worden gemaakt (en opnieuw worden getest) om de wijzigingen vervolgens op een geschikt moment in productie te brengen en dan pas in productie de instelling ‘Compatibility Level’ te wijzigen.

Moet de instelling worden gewijzigd?
Nee, het moet niet, voor zolang Microsoft de huidige compatibility level ondersteunt. Of het verstandig is om het niet te doen, is een tweede. Ik kan mij voorstellen dat ook uw organisatie met de laatste inzichten en technieken wilt werken. Dan is het echt noodzakelijk om de tests uit te voeren en uiteindelijk de productie-database naar het juiste niveau te brengen.

SQL Server tabel hernoemen (sp_rename)

Denk goed na over de gevolgen van het hernoemen van tabellen in een SQL Server database!

Problemen waar ik regelmatig tegen aan loop, is dat objecten (vaak primary keys) niet in de nieuwe naamconventie zijn meegenomen. Bijvoorbeeld de tabel dbo.tblIndex wordt hernoemd naar dbo.tblIndexArchive. Echter op deze tabel staat een primary key met de naam PK_tblIndex_IndexId. Vervolgens wordt de tabel dbo.tblIndex opnieuw aangemaakt en geeft het aanmaken van de primary key een foutmelding, omdat die naam al binnen de tabel dbo.tblIndexArchive is gebruikt. Onderstaand TestLab iillustreert en verduidelijkt het probleem.

/*

Datum			: 5 januari 2024
Ontwikkelaar	: Mickel Reemer

Doel van het script:
--------------------
Inzage geven in gevolgen van het hernoemen van een tabel
zonder voldoende rekening te houden met de naamconventie
van objecten (zoals indexen) binnen die tabel.
*/

-- Verwijder de testtabellen wanneer ze aanwezig zijn
DROP TABLE IF EXISTS dbo.tblIndex;
DROP TABLE IF EXISTS dbo.tblIndexArchive;

-- Maak de tabel dbo.tblIndex aan en plaats een primary key op de tabel
CREATE TABLE dbo.tblIndex (
	IndexId		INT IDENTITY (1,1),
	IndexName	NVARCHAR(100),
	Remarks		NVARCHAR(200),
	CONSTRAINT PK_tblIndex_IndexId PRIMARY KEY CLUSTERED (IndexId)
);

-- Maak een index op de tabel dbo.tblIndex aan
CREATE INDEX tblIndex_IndexName ON dbo.tblIndex (IndexName);

-- Vul de tabel dbo.tblIndex met testrecords
INSERT INTO dbo.tblIndex (
	IndexName,
	Remarks
)
VALUES	('Index 1','Remark 1'),
		('Index 2','Remark 2'),
		('Index 3','Remark 3'),
		('Index 4','Remark 4'),
		('Index 5','Remark 5'),
		('Index 6','Remark 6'),
		('Index 7','Remark 7');

-- Hernoem de tabel dbo.tblIndex naar dbo.tblIndexArchive
EXEC sp_rename 'dbo.tblIndex', 'tblIndexArchive';

-- Maak de tabel dbo.tblIndex opnieuw aan met een primary key
CREATE TABLE dbo.tblIndex (
	IndexId		INT IDENTITY (1,1),
	IndexName	NVARCHAR(100),
	Remarks		NVARCHAR(200),
	CONSTRAINT PK_tblIndex_IndexId PRIMARY KEY CLUSTERED (IndexId)
);

/*
Het opnieuw aanmaken van de tabel geeft dus een foutmelding
omdat de naam van de primary key al in de tabel dbo.tblIndexArchive
bestaat.

Mijn advies zou zijn om eerst alle objecten binnen de tabel
dbo.tblIndexArchive te wijzigen naar de juiste naamconventie
en vervolgens pas de nieuwe tabel aan te maken.
*/

Belangrijk
Vergeet de naamconventie van de statistics niet te bekijken!

Windows GodMode

Microsoft heeft het mogelijk gemaakt om toegang te krijgen tot elke mogelijke setting in Windows. Dit wordt de “God Mode” genoemd. Hoe?

  • Maak een nieuwe folder op uw bureaublad aan
  • Hernoem de folder naar GodMode.{ED7BA470-8E54-465E-825C-99712043E01C} (kopiëren / plakken!)
  • De folder wordt nu een soort control panel icoontje
  • Open het control panel icoontje
  • … u beschikt nu over alle mogelijke windows instellingen

Handig? Ik weet het nog niet zeker, maar het werkt voor Windows 10 als voor Windows 11.