PowerShell Üzerinde Power BI Kullanımı — Zamanlanmış Yenileme İşlemleri
Merhabalar, iyi günler.
Bugün Microsoft’un birbirinden bağımsız veri kaynaklarınızı tutarlı, görsel olarak sürükleyici ve etkileşimli öngörülere dönüştürmenizi sağlamak için birlikte çalışan yazılım hizmetlerinden, uygulamalardan ve bağlayıcılardan oluşan bir koleksiyonu olan Power BI’ın PowerShell üzerinde veri kaynağı özelliği olan Zamanlanmış Yenileme (Schedule Refresh) hakkında neler yapılabileceğine yönelik aktarımlarda bulunmaya çalışacağım.
Şimdiden iyi okumalar.
***
Geçmiş PowerShell yazılarımızda;
- PowerShell üzerinde Power BI kullanımı, (EK)
- PowerShell üzerinden Power BI kaynakları listesi elde edilmesi, (EK)
- PowerShell üzerinden Power BI kullanıcı listesi elde edilmesi, (EK)
- PowerShell üzerinden Power BI Kullanıcı dökümleri/özetleri elde edilmesi, (EK)
- PowerShell üzerinden Power BI kullanıcı eylemleri/işlemleri elde edilmesi, (EK)
- PowerShell üzerinden Power BI mevcut kaynak listesi elde edilmesi, (EK)
- PowerShell üzerinden Power BI kaynak çalışma durumlarının dökümleri/özetleri elde edilmesi (EK)
- PowerShell üzerinden Power BI raporlarının yedeklenmesi (EK)
konularına yönelik aktarımlarda bulunmuştuk.
Bu yazıda da yönetilebilir bir sistem oluşturmaya yönelik çalışmalarımıza devam ederek;
- Mevcut raporların yenileme planlarını günbegün kayıt altına alma,
- Veri kaynaklarını genel ve veri kaynağı bazlı yenileme
konularını ele almaya çalışacağız.
Dilerseniz hızlıca önceki yazılarımızla edindiğimiz bilgiler dahilinde işlemlere başlayalım.
Kurgu olarak; Power BI üzerindeki çalışma alanlarına, oradanda ilgili veri kaynağı bilgilerine ulaşıp; servis üzerinden bu bilgileri yerel alanımızdaki veri kaynağımıza aktarmaya çalışacağız.
Öncelikle hızlıca Power BI hizmetine bağlanalım;
*Önceki yazılarda detaylara yer verilmiştir.
$PBIAdminUPN = "bilgi@miracozturk.com"
$PBIAdminPW = "ADMIN PAROLANIZ"
$SecurePassword = ConvertTo-SecureString $PBIAdminPW -AsPlainText -Force
$Credential = New-Object System.Management.Automation.PSCredential($PBIAdminUPN,$SecurePassword)
Görüntülendiği gibi servise erişebiliyoruz, ikinci adım olarak ise çalışma alanlarımıza ulaşmamız gerekiyor.
Önceki çalışmalarımızdan edindiğimiz bilgiler dahilinde çalışma alanlarına ulaşalım;
$Workspaces = Get-PowerBIWorkspace
foreach($workspace in $Workspaces)
{
"Çalışma Alanı ID: " + $workspace.Id + " -***- " + "Çalışma Alanı Adı: "+ $workspace.Name
}
Şuan çalışma alanlarına ulaşabilir durumdayız.
Peki; genel olarak raporlarımızın veri kaynaklarına (Dataset) ulaşmayı deneyelim;
foreach($workspace in $Workspaces)
{
"Çalışma Alanı ID: " + $workspace.Id + " -***- " + "Çalışma Alanı Adı: "+ $workspace.Name
$DataSets = Get-PowerBIDataset -WorkspaceId $workspace.Id | where {$_.isRefreshable -eq $true}
foreach($dataset in $DataSets)
{
"Veri Kaynagi ID: " + $dataset.Id + " -***- " + "Veri Kaynagi Adı: "+ $dataset.Name
}
}
rapor veri kaynağı erişimimiz ile de ilgili bir problem gözükmemektedir.
Şimdi ise ilgili veri kaynaklarına ait Zamanlanmış Yenileme (Schedule Refresh) bilgilerine ulaşalım.
Bunun için sırası ile;
- Organizasyon grubu,
- Çalışma alanı,
- Veri kaynağı,
- Yenileme bilgisi alanına
ulaşacak olan bağlantımızı kurgulamamız gerekmektedir.
Servis erişimi ardından ilgili API erişim bağlantımızı düzenleyerek;
$URI = "groups/" + $workspace.Id + "/datasets/" + $dataset.id + "/refreshSchedule"
formatında kullanım sağlayabiliriz.
Bunu Power BI servis üzerindeki API hizmetinde kullanarak;
$Results = Invoke-PowerBIRestMethod -Url $URI -Method Get | ConvertFrom-Json
bilgilerimize ulaşmaya çalışacağız.
Son düzenlemler dahilinde genel kod bloğumuzu düzenleyecek olursak;
foreach($workspace in $Workspaces)
{
"Çalışma Alanı ID: " + $workspace.Id + " -***- " + "Çalışma Alanı Adı: "+ $workspace.Name
$DataSets = Get-PowerBIDataset -WorkspaceId $workspace.Id | where {$_.isRefreshable -eq $true}
foreach($dataset in $DataSets)
{
"Veri Kaynagi ID: " + $dataset.Id + " -***- " + "Veri Kaynagi Adı: "+ $dataset.Name
$URI = "groups/" + $workspace.Id + "/datasets/" + $dataset.id + "/refreshSchedule"
$Results = Invoke-PowerBIRestMethod -Url $URI -Method Get | ConvertFrom-Json
if($Results.enabled -eq $true)
{
$Results
}
}
}
şeklinde olacaktır.
Peki hızlıca çalıştırarak bir testte bulunalım;
- @odata.context (Open Data Protocol Context — Açık Veri Protokolü Bağlamı): API hizmetinin bağlantı bilgisi yer almaktadır.
- days (Günler): Veri kaynağına yönelik zamanlanmış yenileme gerçekleştirilecek günlerin bilgisi yer almaktadır.
- times (Zamanlar): Veri kaynağına yönelik zamanlanmış yenileme gerçekleştirilecek günlerdeki zaman bilgisi yer almaktadır.
- enabled (Etkinleştirilmiş mi): Veri kaynağına yönelik zamanlanmış yenileme durumu bilgisi yer almaktadır.
- localTimeZoneId (Yerel Saat Dilimi Kimliği): Veri kaynağına yönelik zamanlanmış yenileme gerçekleştirilecek zaman standartları bilgisi yer almaktadır.
- notifyOption (Seçenek Bildirme): Veri kaynağına yönelik zamanlanmış yenileme bildirim bilgisi yer almaktadır.
bilgilerine ulaşabildiğimizi görüntülemekteyiz.
Buraya kadar verikaynağı zamanlanmış yenileme bilgilerine ulaşma kurgumuzu tamamladık; peki bu noktadan sonra önceki yazılarımızda kurgulamış olduğumuz takip sistemi adına ne gibi bilgiler sağlayabiliriz?
Tekrardan MsSQL üzerine geri dönüp bu bilgileri bir veritabanı üzerindeki tabloya yazarak işlem geçmişi bilgisi oluşturabiliriz.Burada ki hedefimiz; büyük bir organizasyonel yapıda sunucu üzerinde ki yük takibini ve raporlardaki yenileme değişimlerinin takibini gerçekleştirebilmek.
Sonrasında bu yapı; yenileme hatası almış veri kaynakları için parametrik yenileme öncesi yenileme geçmişi kontrolünde bulunabilmemizi sağlayacaktır.
Peki; öncelikle hangi parametrelerin işlem geçmişinde yer alacağı ve nasıl aktarılacağını belirleyelim.
Aktarılacak olan parametreler olarak;
- LogDate: İlgili kayıt işleminin gerçekleştiği zaman.
- WorkspaceId: Veri kaynağının yer aldığı çalışma alanı.
- DatasetName: İlgili verikaynağı adı.
- Days: İlgili veri kaynağı zamanlanmış yenileme günleri.
- Times: İlgili veri kaynağı zamanlanmış yenileme zamanı.
- Enabled: Veri kaynağına yönelik zamanlanmış yenileme durumu.
- NotifyOption Veri kaynağı bilgilendirme durumu.
- LocalTimeZoneId: Veri kaynağı zamanlanmış yenileme bölge zaman formatı.
bilgileri şuanlık takip altına alınabilir.
O halde sorgumuzu parametrelerimiz dahilinde düzenleyelim.
Zamanlanmış yenileme bilgileri adına aktarım yapacak formatımızın önizlemesi alt kısımda yer alan görseldeki gibi olacaktır;
foreach($workspace in $Workspaces)
{
$DataSets = Get-PowerBIDataset -WorkspaceId $workspace.Id | where {$_.isRefreshable -eq $true}
foreach($dataset in $DataSets)
{
$URI = "groups/" + $workspace.Id + "/datasets/" + $dataset.id + "/refreshSchedule"
$Results = Invoke-PowerBIRestMethod -Url $URI -Method Get | ConvertFrom-Json
if($Results.enabled -eq $true) {
$LogDate1=Get-Date -Format "dddd MM/dd/yyyy HH:mm K"
$Workspace1=$workspace.Id
$Dataset1=$Dataset.Name
$Days1=$Results.days
$Times1=$Results.times
$Enabled1=$Results.enabled
$NotifyOption1=$Results.notifyOption
$LocalTimeZone1=$Results.localTimeZoneId
$insertquery="
INSERT INTO
$tableName
(
[LogDate]
,[WorkspaceId]
,[DatasetName]
,[Days]
,[Times]
,[Enabled]
,[NotifyOption]
,[LocalTimeZoneId]
)
VALUES
(
'$LogDate1',
'$Workspace1',
'$Dataset1',
'$Days1',
'$Times1',
'$Enabled1',
'$NotifyOption1',
'$LocalTimeZone1'
)"
$Command.CommandText = $insertquery
$Command.ExecuteNonQuery()
}
}
}
$Connection.Close()
Yanı sıra ADO.Net tanımlamalarınıda hızlıca oluşturarak ana kod bloğumuza ekleyelim;
$serverName = " SUNUCU ADINIZ "
$databaseName = " ILGILI VERITABANI "
$tableName = " ILGILI TABLO "
$Connection = New-Object System.Data.SQLClient.SQLConnection
$Connection.ConnectionString = "server='$serverName';database='$databaseName';trusted_connection=true;"
$Connection.Open()
$Command = New-Object System.Data.SQLClient.SQLCommand
$Command.Connection = $Connection
MsSQL tarafındaki zamanlanmış yenileme işlem geçmişi veri bilgilerini kayıt altına alacak tablomuz ise;
*Bireysel SQL formatı görünümü.
USE [PowerBIServiceLog]
GO
/****** Object: Table [dbo].[ScheduleRefresh] Script Date: 31.03.2023 21:52:09 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[ScheduleRefresh](
[LogDate] [nvarchar](50) NULL,
[WorkspaceId] [nvarchar](250) NULL,
[DatasetName] [nvarchar](250) NULL,
[Days] [nvarchar](100) NULL,
[Times] [nvarchar](50) NULL,
[Enabled] [nvarchar](5) NULL,
[NotifyOption] [nvarchar](50) NULL,
[LocalTimeZoneId] [nvarchar](50) NULL
) ON [PRIMARY]
GO
formatında olacaktır.
Tüm bilgilerimizi derleyip kod bloğumuzu yeniden yapılandırdığımızda;
$PBIAdminUPN = " ORGANIZASYON YONETICI KULLANICINIZ "
$PBIAdminPW = " ORGANIZASYON YONETICI KULLANICISI PAROLANIZ "
$SecurePassword = ConvertTo-SecureString $PBIAdminPW -AsPlainText -Force
$Credential = New-Object System.Management.Automation.PSCredential($PBIAdminUPN,$SecurePassword)
$serverName = " SUNUCU ADINIZ "
$databaseName = " ILGILI VERITABANI "
$tableName = " ILGILI TABLO "
$Connection = New-Object System.Data.SQLClient.SQLConnection
$Connection.ConnectionString = "server='$serverName';database='$databaseName';trusted_connection=true;"
$Connection.Open()
$Command = New-Object System.Data.SQLClient.SQLCommand
$Command.Connection = $Connection
Connect-PowerBIServiceAccount -Credential $Credential
$Workspaces = Get-PowerBIWorkspace
foreach($workspace in $Workspaces)
{
$DataSets = Get-PowerBIDataset -WorkspaceId $workspace.Id | where {$_.isRefreshable -eq $true}
foreach($dataset in $DataSets)
{
$URI = "groups/" + $workspace.Id + "/datasets/" + $dataset.id + "/refreshSchedule"
$Results = Invoke-PowerBIRestMethod -Url $URI -Method Get | ConvertFrom-Json
if($Results.enabled -eq $true) {
$LogDate1=Get-Date -Format "dddd MM/dd/yyyy HH:mm K"
$Workspace1=$workspace.Id
$Dataset1=$Dataset.Name
$Days1=$Results.days
$Times1=$Results.times
$Enabled1=$Results.enabled
$NotifyOption1=$Results.notifyOption
$LocalTimeZone1=$Results.localTimeZoneId
$insertquery="
INSERT INTO
$tableName
(
[LogDate]
,[WorkspaceId]
,[DatasetName]
,[Days]
,[Times]
,[Enabled]
,[NotifyOption]
,[LocalTimeZoneId]
)
VALUES
(
'$LogDate1',
'$Workspace1',
'$Dataset1',
'$Days1',
'$Times1',
'$Enabled1',
'$NotifyOption1',
'$LocalTimeZone1'
)"
$Command.CommandText = $insertquery
$Command.ExecuteNonQuery()
}
}
}
$Connection.Close()
görüntüsünü elde etmekteyiz.
Herşey hazır olduğuna göre ana PowerShell kod ekranımıza dönüp ilgili kodumuzu çalıştıralım;
Önceki yazılarımızdan aşina olduğumuz herbir log kaydı için 1’lerin olduğu bir çıktı görüntülüyoruz.
Peki MsSQL üzerindeki tablomuza dönecek olursak;
işlem geçmişi bilgilerimizin kayıt altına alındığını görüntülüyoruz.
NOT: Burada dikkat edilmesi gereken nokta ise; zamanlanmış yenileme planı oluşturulmuş olan veri kaynaklarının ilgili bilgilerine ulaşabildik.
Buraya kadar olan kısımda çalışma alanlarımızda yer alan veri kaynaklarının zamanlanmış yenileme planlarına ulaştık.Bu noktadan sonra bu yenilemeleri plan dışı olarak nasıl çalıştırabileceğimize göz atalım.
Hade biraz eğlenelim.
Öncelikle Visual Studio* üzerinde temel seviyede bir C# Console Application (Konsol Uygulaması) oluşturalım.
IDE tercihi sizlere bağlı.
Şimdi mevcut PowerShell kod yapımızı C# üzerinde çalışabilecek formata uyarlamaya çalışalım.
Öncelikle kodlarımızı çalıştırabilmek için Nuget* üzerinden birtakım kütüphaneleri yüklememiz gerekmektedir.
Nuget: .NET platformu ile yazılım geliştirirken kullanılan harici paketlerin yönetimini sağlayan hizmettir.
Bunlar;
Microsoft.Identity.Client;
Microsoft.PowerBI.Api;
System.Management.Automation
Elbetteki versiyonları kullanacağınız projeye yönelik değişecektir.
Projemizdeki kütüphaneler ve versiyonlar;
şeklindedir.
Bir sonraki adımımızda; uygulama üzerinde AUTH gerçekleştirmek ve API kullanım işleminde bulunabilmek için bize ClientID (ApplicationID) ve TenantID bilgileri gerekecektir.
TenantID bilgisine,
https://portal.azure.com/#view/Microsoft_AAD_IAM/TenantPropertiesBlade
bağlantısı üzerinden;
görseldeki şekilde erişebilirsiniz.
ClientID (ApplicationID) bilgisine,
https://app.powerbi.com/embedsetup/AppOwnsData
bağlantısı üzerinden;
erişebilirsiniz.
Bu bilgiler ile, aşağıdaki bağlantılarımızdan yararlanarak kod bloğumuzu kurmaya başlayalım.
- Microsoft Power BI REST API:
https://docs.microsoft.com/en-us/rest/api/power-bi/ - Microsoft.PowerBI.Api NuGet paketi:
https://www.nuget.org/packages/Microsoft.PowerBI.Api/ - Microsoft.Identity.Client NuGet paketi:
https://www.nuget.org/packages/Microsoft.Identity.Client/ - Azure AD ile Kullanıcı adı ve Parola Kimlik Doğrulaması:
https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth-ropc
Öncelikle erişim için kod bloğumuzu adım adım düzenleyelim.
- clientId, tenantId, username ve password bilgilerini dinamik olarak kullanabilmek için birer parametreye atayalım,
- authority yetkilendirme bağlantımızı da tenantId ile kullanılacak şeklide parametrik olarak düzenleyelim,
- app değişkeni oluşturup; kimlik doğrulama için kullanılacak istemci uygulamasını yapılandıralım,
Burada; PublicClientApplicationBuilder.Create yöntemi kullanarak bir PublicClientApplication nesnesi oluşturuyoruz. - token değişkeni oluşturup; AcquireTokenByUsernamePassword yöntemi ile kullanıcının kimlik bilgilerini kullanarak bir erişim belirteci hazırlayalım,
Bu belirteç, API’ye erişim yapmak için kullanılacak yetkilendirme belirtecidir. - Son olarak ise; tokenCredentials değişkeni oluşturup, API istekleri için kullanılacak TokenCredentials nesnesini oluşturalım.
Bu işlemler sonrası kod bloğumuzun son hali ise;
string clientId = "CLIENT ID";
string tenantId = "TENANT ID";
string username = "USER NAME";
string password = "PASSWORD";
string authority = $"https://login.microsoftonline.com/{tenantId}";
var app = PublicClientApplicationBuilder.Create(clientId)
.WithAuthority(authority)
.Build();
var token = await app.AcquireTokenByUsernamePassword(new[]
{ "https://analysis.windows.net/powerbi/api/.default" },
username, password.ToString()).ExecuteAsync();
var tokenCredentials = new TokenCredentials(token.AccessToken, "Bearer");
şeklindedir.
Şimdi bu bilgilerimiz ile PowerBIClient nesnesi oluşturularak, API’ye erişim sağlayalım;
using (var client = new PowerBIClient(new Uri("https://api.powerbi.com"), tokenCredentials))
Ardından parametrik bir şekilde Çalışma Alanlarına erişme adına workspace parametresi oluşturup, GetGroupsAsync yöntemi ile tüm çalışma alanlarına ulaşalım;
var workspaces = await client.Groups.GetGroupsAsync();
Sonrasında ise çalışma alanları altında yer alan veri kaynaklarımıza ulaşıp, RefreshDatasetInGroupAsync yöntemiyle tüm veri kümesi bilgilerini alalım;
foreach (var workspace in workspaces.Value)
{
var datasets = await client.Datasets.GetDatasetsInGroupAsync(workspace.Id);
}
Ve son olarak bu veri kaynaklarını yenileyelim.
Bu noktada yenilemeleri konsol üzerinde görebilmek için ise ufak bir kod daha ekleyip, her bir yenileme işlemi öncesinde bunu konsola yazdıralım.Bunun için ise alt kısımdaki çalışma alanı ve veri kaynağı bilgisini içeren formatı kullanabiliriz;
foreach (var dataset in datasets.Value)
{
Console.WriteLine($"Refreshing {dataset.Name} in {workspace.Name}");
await client.Datasets.RefreshDatasetInGroupAsync(workspace.Id, dataset.Id);
}
Tüm bu kodları düzenleyecek olursak;
using Microsoft.Identity.Client;
using Microsoft.PowerBI.Api;
using Microsoft.Rest;
class Program
{
static async Task Main(string[] args)
{
string clientId = "CLIENT ID";
string tenantId = "TENANT ID";
string username = "USERNAME";
string password = "PASSWORD";
string authority = $"https://login.microsoftonline.com/{tenantId}";
var app = PublicClientApplicationBuilder.Create(clientId)
.WithAuthority(authority)
.Build();
var token = await app.AcquireTokenByUsernamePassword(new[]
{ "https://analysis.windows.net/powerbi/api/.default" },
username, password.ToString()).ExecuteAsync();
var tokenCredentials = new TokenCredentials(token.AccessToken, "Bearer");
using (var client = new PowerBIClient(
new Uri("https://api.powerbi.com"),
tokenCredentials)
)
{
var workspaces = await client.Groups.GetGroupsAsync();
foreach (var workspace in workspaces.Value)
{
var datasets = await client.Datasets.GetDatasetsInGroupAsync(workspace.Id);
foreach (var dataset in datasets.Value)
{
Console.WriteLine($"Refreshing {dataset.Name} in {workspace.Name}");
await client.Datasets.RefreshDatasetInGroupAsync(workspace.Id, dataset.Id);
}
}
}
}
}
şeklinde konsol uygulmamız görüntülenmektedir.
Dilerseniz şimdi uygulamamızı çalıştıralım;
hata almadan uygulmamız çalıştı.
Peki, Power BI Service üzerindeki durum ne?
yenileme gözlemliyoruz.
Ama bu zamanlanmış yenilemeden dolayı mı, yoksa bizim API isteğimizden mi?
Veri kaynağı yenileme detaylarına bakalım;
Evet, yenileme API isteğimizden kaynaklı.
Şuan tüm süreçlemiz aktif olarak hatasız bir şekilde çalışmaktadır.
Peki bunlarla ne yapmayı hedefleyebiliriz?
Günümüzde kurumsal kaynaklar üzerindeki süreçler Organizasyon Admin bilgilerini ikinci bir kullanıcı ile paylaşma durumunda ortaya büyük riskler çıkarmaktadır.
Geçmiş PowerShell yazılarımızla mevcut yazımızı birleştirip; C# ile bir Power BI Yönetim Uygulaması/Paneli geliştirilebilirsiniz.
Bu panel üzerine;
- Tüm kaynak bilgilerini denetleyip; takip edebilir, (Kullanıcılar, Çalışma Alanları, Raporlar, Panolar…)
- Kullanıcı işlem geçmişini denetleyip; takip edebilir,
- Öğe çalışma işlem geçmişini denetleyip; takip edebilir,
- Öğe yedekleme işlem geçmişini denetleyip; takip edebilir,
ve daha ek özellikler eklenerek güvenlikli bir ikinici Power BI Service yönetim alanı inşaa edilip, yeni bir yönetici ekibi için çalışma alanı oluşturabilirsiniz.
Büyük ölçekteki bir organizasyonsanız fazlası ile faydasını göreceksiniz…
İlgili işlemlere ait kod dökümlerine;
- PowerShell zamanlanmış yenileme kodları için lütfen tıklayınız…
- C# uygulaması için lütfen tıklayınız…
bağlantıları üzerinden erişebilirsiniz.
Umarım faydalı olur.
Gelecek yazılarda görüşmek üzere.
İyi çalışmalar…