There were a few FIM reporting sessions at TEC, none of which I managed to make it to, though I hope the presenters will be making their solutions generally available as they are undoubtably more correct and complete than what I’ve been doing. However a couple of people did ask that I post my method which is, in my usually simplistic DIY fashion, a rip of data direct from the FIMService DB using queries.
Note: this workaround should become redundant with R2 which includes archiving of request data. In the meantime I’ve also added another method to archive details about Approvals.
Create Reporting Tables
Start by creating the following tables in the database you use for reporting (ie NOT one of the DBs installed by FIM. I have a dedicated DB called “FIMReporting”):
USE [FIMReporting] CREATE TABLE [dbo].[fim_requests_new]( [ObjectKey] [nvarchar](50) NULL, [Attribute] [nvarchar](50) NULL, [Value] [nvarchar](max) NULL ) ON [PRIMARY]
USE [FIMReporting] CREATE TABLE [dbo].[fim_requests_log]( [ObjectKey] [nvarchar](150) NULL, [Creator] [nvarchar](150) NULL, [CreatedTime] [nvarchar](150) NULL, [CommittedTime] [nvarchar](150) NULL, [Operation] [nvarchar](150) NULL, [Target] [nvarchar](150) NULL, [TargetObjectType] [nvarchar](150) NULL, [ManagementPolicy] [nvarchar](500) NULL, [RequestStatus] [nvarchar](150) NULL, [RequestParameter] [nvarchar](max) NULL ) ON [PRIMARY]
Extract recent requests
Once an hour, at the end of the regular sync cycle, I run this SQL script to copy out the requests I haven’t yet logged:
truncate table FIMReporting.dbo.fim_requests_new; insert into FIMReporting.dbo.fim_requests_new select o.ObjectKey, 'ObjectKey' as Attribute, o.ObjectKey as Value from FIMService.fim.Objects o left outer join dbo.fim_requests_log l on o.ObjectKey = l.ObjectKey inner join FIMService.fim.ObjectValueString s on o.ObjectKey = s.ObjectKey where o.ObjectTypeKey = 26 and l.ObjectKey is null and s.AttributeKey = 66; insert into FIMReporting.dbo.fim_requests_new select v.ObjectKey, a.Name as Attribute, CAST(v.ValueBoolean as nvarchar) as Value from FIMService.fim.ObjectValueBoolean v join FIMService.fim.AttributeInternal a on v.AttributeKey = a.[Key] join FIMReporting.dbo.fim_requests_new n on v.ObjectKey = n.ObjectKey where n.Attribute = 'ObjectKey'; insert into FIMReporting.dbo.fim_requests_new select v.ObjectKey, a.Name as Attribute, CAST(v.ValueDateTime as nvarchar) as Value from FIMService.fim.ObjectValueDateTime v join FIMService.fim.AttributeInternal a on v.AttributeKey = a.[Key] join FIMReporting.dbo.fim_requests_new n on v.ObjectKey = n.ObjectKey where n.Attribute = 'ObjectKey'; insert into FIMReporting.dbo.fim_requests_new select v.ObjectKey, a.Name as Attribute, CAST(ValueInteger as nvarchar) as Value from FIMService.fim.ObjectValueInteger v join FIMService.fim.AttributeInternal a on v.AttributeKey = a.[Key] join FIMReporting.dbo.fim_requests_new n on v.ObjectKey = n.ObjectKey where n.Attribute = 'ObjectKey'; insert into FIMReporting.dbo.fim_requests_new select v.ObjectKey, a.Name as Attribute, name.ValueString as Value from FIMService.fim.ObjectValueReference v join FIMService.fim.AttributeInternal a on v.AttributeKey = a.[Key] join FIMReporting.dbo.fim_requests_new n on v.ObjectKey = n.ObjectKey join FIMService.fim.Objects ref on v.ValueReference = ref.ObjectKey join FIMService.fim.ObjectValueString name on ref.ObjectKey = name.ObjectKey where n.Attribute = 'ObjectKey' and name.AttributeKey = 66; insert into FIMReporting.dbo.fim_requests_new select v.ObjectKey, Name as Attribute, ValueString as Value from FIMService.fim.ObjectValueString v join FIMService.fim.AttributeInternal a on v.AttributeKey = a.[Key] join FIMReporting.dbo.fim_requests_new n on v.ObjectKey = n.ObjectKey where n.Attribute = 'ObjectKey'; insert into FIMReporting.dbo.fim_requests_new select v.ObjectKey, Name as Attribute, ValueText as Value from FIMService.fim.ObjectValueText v join FIMService.fim.AttributeInternal a on v.AttributeKey = a.[Key] join FIMReporting.dbo.fim_requests_new n on v.ObjectKey = n.ObjectKey where n.Attribute = 'ObjectKey';
Pivot query
I then have to run another SQL script to pivot the data so I end up with one line per request in my log table:
use FIMReporting insert into dbo.fim_requests_log SELECT ObjectKey,Creator,CreatedTime,CommittedTime,Operation,[Target], TargetObjectType,ManagementPolicy,RequestStatus,RequestParameter FROM (select * from dbo.fim_requests_new where ObjectKey in ( select ObjectKey from dbo.fim_requests_new where Attribute = 'RequestStatus' and Value in ('Completed','Failed','Denied','PostProcessingError') )) as src PIVOT ( MAX(Value) FOR Attribute IN ( Creator,CreatedTime,CommittedTime,Operation,[Target],TargetObjectType,ManagementPolicy,RequestStatus,RequestParameter) ) AS pvt;
Pruning
As I don’t want the data in this log to build up and up I have a third script which I run once a day to prune records. I do this in two steps – first I get rid of requests made by the service accounts, and later I delete all requests.
use FIMReporting declare @pruneDays as int declare @deleteDays as int set @pruneDays = 50 /* Must be greater than number of day kept in FIMService DB */ set @deleteDays = 180 declare @today as nvarchar(50) set @today = GetDate() delete from dbo.fim_requests_log where datediff(day,CONVERT(datetime,CreatedTime),@today) > @deleteDays /* Prune service account requests. YOUR ACCOUNT NAMES WILL VARY. */ delete from dbo.fim_requests_log where datediff(day,CONVERT(datetime,CreatedTime),@today) > @pruneDays and Creator in ('s-fimportal', 'Forefront Identity Manager Service Account', 'Built-in Synchronization Account')