Zobrazují se příspěvky se štítkemPowerShell. Zobrazit všechny příspěvky
Zobrazují se příspěvky se štítkemPowerShell. Zobrazit všechny příspěvky

čtvrtek 4. března 2010

PowerShell - informace o AX aplikaci

Snažíte se psát skripty pro manipulaci s AX a nechce se vám udržovat informace o jménech aplikací, cestách k adresářům a podobně? Mně se tedy nechce a tak jsem si řekl, že bych mohl všechno zjistit automatizovaně jen na základě .axc souboru. Výstup mého skriptu vypadá následovně:
AppLocalPath       : C:\Program Files\Microsoft Dynamics AX\50\Application\Appl\JmenoAplikace
AosName            : JmenoAOS
AosNumber          : 03
AosServiceInstance : System.ServiceProcess.ServiceController
AosPort            : 2714
AosComputerName    : JmenoPocitaceSAos.domena
AppUncPath         : \\JmenoPocitaceSAos\C$\Program Files\(...)\Appl\JmenoAplikace
Základní informace o AOS zjistím se zadaného .axc souboru, instanci služby pomocí Get-Service a cestu k aplikačnímu adresáři z registrů počítače, kde je nainstalované AOS. Z toho také plyne, že je třeba mít nakonfigurovaný PowerShell remoting. Podrobnosti zde nebudu rozepisovat, zájemci si pročtou kód a nezájemci ušetří čas :-). Skript stahujte zde.

středa 27. ledna 2010

Seznam přihlášených uživatelů

Dnešní příspěvek je opravdu dlouhý, ale ve skutečnosti popisuje vcelku jednoduchou věc - PowerShellový skript pro snadné získání seznamu přihlášených uživatelů. Taková informace je při údržbě AX prostředí potřeba dost často, pokud chcete brát ohledy na přihlášené uživatele a nevypínat jim služby pod rukama. Lze se samozřejmě přihlásit do AX, otevřít modul Administrace, formulář Uživatelé online a tam ověřit, zda je někdo přihlášený. To ale dost zdržuje a tak jsem si tento úkol trochu zjednodušil skriptem, který umožní zvolit konfigurační soubor Dynamics AX, připojí se pomocí Business Connectoru a vypíše přihlášené uživatele do konzolového okna. Trochu blíže k předpokladům pro tento skript:
  • Konfigurační soubory (.axc) pro všechna prostředí jsou uložena v jednom adresáři (viz proměnnou $configurationPath) a týkají se Dynamics AX 2009. V tomto ohledu jsem jen využil existující systém v naší firmě, vy si možná budete muset skript upravit.
  • Nainstalovaný Business Connector
  • PowerShell 2.0
  • .NET 3.0+ (kvůli WPF)
První skript příjmá jako parametr ($args[0]) jméno konfiguračního souboru. Načte sestavení BussinessConnectorNet.dll, vytvoří objekt typu Axapta a zaloguje se pomocí konfiguračního souboru (v něm je adresa AOS atd.). V dalším kroku se dotáže na uživatelská připojení (tabulka SysClientSessions), popř. další informace o uživateli a AOS. Tyto informace zabalí do objektu (což usnadňuje další zpracování) a ten předá na výstup. Ukázka výsledku: Zdrojový kód vypadá takto (některé řádky byly kvůli přehlednosti zalomeny):
$connectorDllPath = 'C:\Program Files\Microsoft Dynamics AX\50\' `
    + 'Client\Bin\Microsoft.Dynamics.BusinessConnectorNet.dll'
$configurationPath = 'D:\CONFIGURATIONS'
$configurationName = $args[0]
$configFile = Join-Path $configurationPath $configurationName

if (!(Test-Path $configFile))
{
    throw "Konfigurace $configFile nebyla nalezena"
}

#zalogování do AX pomocí Business Connectoru
try
{
    [void][reflection.Assembly]::Loadfile($connectorDllPath)
    $ax = New-Object Microsoft.Dynamics.BusinessConnectorNet.Axapta
    $ax.logon('', '', '', $configFile)
}
catch
{
    throw 'Přihlášení pomocí Business Connectoru se nezdařilo'
}

#objekty představující AX tabulky
$sysClientSessions = $ax.CreateAxaptaRecord('SysClientSessions');
$sysServerSessions = $ax.CreateAxaptaRecord('SysServerSessions');

#dotaz na aktivní uživatele přihlášené přes GUI
$sysClientSessions.ExecuteStmt('select * from %1 where %1.Status == 1 ' `
    + '&& %1.ClientType == 0');
if (!$sysClientSessions.Found)
{
    '0 aktivních uživatelů'
}

#iterace přes uživatele, získaní podrobných informací a zabalení do objektu
while ($sysClientSessions.Found)
{
    $userId = $sysClientSessions.get_Field('UserId')
    $userName = $ax.CallStaticClassMethod('UserInfoHelp', 'userName', $userId)

    $sysServerSessions.ExecuteStmt('select * from %1 where %1.ServerId == ' `
       + $sysClientSessions.get_Field('ServerId'))
    $aosInstanceName = $sysServerSessions.get_Field('AOSId')

    #zabalení do objektu
    New-Object PSObject -Property @{
       AosName = $aosInstanceName
       UserId = $userId
       UserName = $userName}

   [void]$sysClientSessions.Next();
}
#odhlášení z AX
[void]$ax.logoff()
Druhý skript slouží k výběru konfigurace AX a jméno této konfigurace předává prvnímu skriptu. Seznam konfigurací je zobrazen v grafickém okně, protože kliknutí mi přišlo jako nejrychlejší způsob výběru. GUI je vytvořeno pomocí WPF (Windows Presentation Foundation) a vypadá takto (s tím rozdílem, že já tam mám konfigurací celkem 42): Seznam konfigurací je naplněn pomocí příkazu Get-ChildItem (alias dir). Zvolená konfigurace ($listBox.SelectedItem) je použita jako parametr pro výše uvedený skript a daný kód je umístěn v obsluze kliknutí na tlačítko ($button.add_Click()).
$configurationPath = 'D:\CONFIGURATIONS'
Add-Type –assemblyName PresentationFramework
Add-Type –assemblyName PresentationCore

Add-Type –assemblyName WindowsBase

$window = New-Object Windows.Window
$window.Title = 'AX konfigurace'
$window.SizeToContent = 'WidthAndHeight'
$label = New-Object Windows.Controls.Label
$label.Content = 'Seznam konfigurací:'

$listBox = New-Object Windows.Controls.Listbox
$listBox.ItemsSource = (% {Get-ChildItem $configurationPath -Include *.axc -Name})

$button = New-Object Windows.Controls.Button
$button.Content = 'Zobraz přihlášené uživatele'
$button.add_Click(
{
    if ($listBox.SelectedItem)
    {
        $window.Hide()
        Write-Host $listBox.SelectedItem

        try
        {
            #volání samostatného skriptu na získání informace o uživatelích
            $activeUsers = (absolutníCesta\prvníSkript.ps1 $listBox.SelectedItem)
        }
        catch
        {
            Write-Host $error[0] -ForegroundColor Red
            exit
        }
   }
})

$stackPanel = New-Object Windows.Controls.StackPanel
$stackPanel.Orientation = 'Vertical'

[void]$stackPanel.Children.Add($label)
[void]$stackPanel.Children.Add($listbox)
[void]$stackPanel.Children.Add($button)

$window.Content = $stackPanel

[void]$window.ShowDialog()

$textbox.Text
$activeUsers
Protože WPF okno vyžaduje běh v STA módu (Single-Threaded Apartment; neznám smysluplný překlad), nelze tento skript spustit běžným způsob. Jednou (a nejjednoduší) možností je zavolání PowerShellu s parametrem -STA, takže spuštěcí příkaz lze napsat (a uložit do .lnk) třeba takto:
C:\WINDOWS\system32\WindowsPowerShell\v1.0\powershell.exe
-STA
-noexit
-command cesta\jmenoSkriptu.ps1

středa 2. prosince 2009

Powershell remoting

V posledních týdnech pracuji spíše okolo Axapty než přímo v ní a v podobném duchu je i tento příspěvek. Jednou z věcí, kterými se zabývám, je totiž automatizace správy Dynamics AX prostředí, zejména instalace programových úprav. PowerShell je pro to ideální nástroj a funkce pro práci po síti - "remoting" - jsou velice potřebné, protože i jednoduchá migrace mezi dvěma Dynamics AX prostředími typicky vyžaduje práci na několika serverech. Nasazování úprav se skládá z mnoha kroků - například zastavování a spouštení AOS, kopírování souborů (vrstev, labelů), importy, kompilace a podobně. Automatizace nejen že sníží čas, který je třeba věnovat celému nasazování, ale sníží i chybovost při práci se soubory a minimalizuje dobu odstávek prostředí. PowerShell remoting v tom může pomoci tak, že celý proces lze řídit z jednoho místa - spravovat služby na vzdálených počítačích, spouštět aplikace, pracovat se soubory, přistupovat k registrům a tak dále. To vše velmi pohodlně a s plnou podporou .NET typů. Na Microsoft Festu 2009 jsem se dozvěděl, že mnoho lidí naráží při pokusech o konfiguraci PowerShell remotingu na problémy, zkusím tedy popsat mé zkušenosti. Musím rovnou říct, že já jsem na žádné příliš závažné problémy nenarazil, tak snad budete stejně úspěšní. První věc, kterou budete potřebovat, je PowerShell verze 2.0. Oproti verzi 1.0 obsahuje řadu nových funkcí, hlavně ale ten zmiňovaný remoting. PowerShell 2.0 je již obsažen v systémech Windows Server 2008 R2 a Windows 7, může ale být samozřejmě nainstalován i do starších systémů a to jako součást Windows Management Frameworku (odkaz obsahuje podrobnější informace včetně podporovaných systémů). Osobně používám PowerShell na WS2008 SP1 a WinXP SP3. Windows Management Framework tedy stáhněte a nainstalujte na všechny počítače, kde chcete PowerShell (i jen vzdáleně) využívat (a pokud nejde o systém, kde již je obsažen). Dále je třeba povolit remoting a to nejlépe pomocí příkazu:
Enable-PSRemoting
Tento příkaz spustí (a nakonfiguruje) službu WinRM, připraví listener očekávající vzdálené příkazy a vytvoří odpovídající pravidlo na firewallu. Toto musí být provedeno jak na serveru, tak i na klientském počítači. Na klientech jsem dále musel změnit konfiguraci sdílení:
Set-ItemProperty –Path HKLM:\System\CurrentControlSet\Control\Lsa –Name ForceGuest –Value 0
a přidat server mezi důvěryhodné. K tomu lze využít následující příkaz:
Set-Item WSMan:\localhost\Client\TrustedHosts –Value MujServer -Force -Concatenate
A to bylo v mém případě vše. :-) Pokud takové štěstí mít nebudete, zkuste se podívat nejprve na about_Remote_Troubleshooting a příbuzná témata, kde je mnoho možných problému popsáno. Off-line můžete zobrazit lokální podobu nápovědy takto:
Get-Help about_Remote_TroubleShooting
Konkrétnímu využití pro nasazování Dynamics AX se budu věnovat někdy v blízké budoucnosti. Dnes uvedu jen jeden jednoduchý příklad - spuštění AOS číslo 2 na vzdáleném stroji MujServer:
$aosService = (Get-Service -Name 'AOS50$02' -ComputerName MujServer)
$aosService.Start()
$aosService.WaitForStatus("Running")
Triviální, nemyslíte?

čtvrtek 3. září 2009

Nasazování úprav pomocí PowerShellu

Nejdřív bleskově pár slov o PowerShellu. PowerShell je (relativně) nový shell, tedy příkazová řádka pro Windows. Je objektový, je postaven na .NET a dobře si rozumí s mnoha komponentami Windows. Je součástí nových Windows (7, 2K8R2) a do starších lze doinstalovat. Vyskytuje se ve dvou hlavních verzích (1 a 2), které se pochopitelně liší funkcionalitou. Detailnější popis není předmětem tohoto postu, zájemcům doporučuji několik odkazů níže. Při nasazování úprav je potřeba udělat spoustu kroků - zastavit AOS, překopírovat vrstvy, labely, spustit AOS… Přímo si to říká o nějakou automatizaci. A PowerShell je pro tento úkol velmi vhodný nástroj. Připravil jsem jeden skript, který ukazuje některé možnosti PowerShellu využitelné pro nasazování úprav v AX. Jde o PowerShell 1.0 a AX2009. Pro AX4 by neměly být třeba žádné změny, u AX3 je situace složitější - například v tom, že AOS v AX3 nemá podobu Windows služby. Nápad volat business connector přímo z PowerShell skriptu jsem si vypůjčil odtud. Věřím, že komentáře v kódu jsou dostačující pro pochopení záměru:
#deklarace proměnných
$aosServiceName = "AOS50`$01"
$axPath = "C:\Program Files\Microsoft Dynamics AX\50"
$axApplPath = "$axPath\Application\Appl\DAX5"

#logování výstupu skriptu do souboru v aktuálním adresáři
$scriptLogName = Get-Date -f "dd-MM-yyyy"
Start-Transcript "$scriptLogName.log" -append -force

#start AOS (pokud neběží)
Start-Service $aosServiceName

#zalogování do AX pomocí business connectoru
[reflection.Assembly]::Loadfile("$axPath\Client\Bin\Microsoft.Dynamics.BusinessConnectorNet.dll")
$ax = New-Object Microsoft.Dynamics.BusinessConnectorNet.Axapta
$ax.logon("","","","")

#výpis počtu sessions (jen pro ukázku)
Write-Host "Sessions:" $ax.CallStaticClassMethod("xSession", "numSession")

#nalezení logovacího souboru kompilace (bude třeba později)
$logFile = Join-Path $ax.CallStaticClassMethod("xInfo", "AOTLogDirectory") "AxCompileAll.html"

#odhlášení z AX
$ax.logoff()

#zastavení AOS, zkopírování souborů, smazání indexů a opětovné spuštění AOS
Stop-Service $aosServiceName
copy "somewhere\*.aod" $axApplPath  #kopírování vrstev
copy "somewhere\*.ald" $axApplPath  #kopírování popisků
rm "$axApplPath\*.ali"              #smazání indexů popisků
rm "$axApplPath\axapd.aoi"          #smazání aplikačního indexu
Start-Service $aosServiceName

#kompilace aplikace
$proc = New-Object System.Diagnostics.Process
$proc.StartInfo.FileName = "$axPath\Client\Bin\Ax32.exe"
$proc.StartInfo.Arguments = "-startupCmd=compileall"
$proc.Start()
$proc.WaitForExit()

#otevření logu kompilace v prohlížeči
Invoke-Item $logFile
Po smazání aplikačního indexu (.aoi) se AOS spouští velmi dlouho, protože vytváří nový index. Kompilaci jsem chtěl původně řešit jako volání:
$ax.CallStaticClassMethod("SysCompileAll","compile")
ale ukázalo se to jako dost nešťastný nápad. Kompilace proběhla, ale ne příliš úspěšně. AX například hlásila chybějící inicializace globálních proměnných (např. infolog), což mě sice pobavilo, nicméně jsem chtěl prostředí ještě někdy používat a musel jsem ho znovu zkompilovat, tentokrát klasicky přes klienta. Ačkoli PowerShell není můj denní chleba a mé příležitostné psaní skriptů zahrnuje jistou dávku objevování, obětovaný čas se rychle vrátí. Navíc člověk dříve nebo později udělá chybu (a třeba smaže jiný soubor než zamýšlel), odladěný skript chyby nedělá. Nicméně skript je program jako každý jiný, je ho tedy třeba otestovat atd. Odkazy: PowerShell homepage PowerShell downloads (na PowerShell blogu) Windows PowerShell 1.0 Documentation Pack Scripting with Windows PowerShell (TechNet) Pokud PowerShell neznáte a chystáte se ho používat, rozhodně se podívejte po vhodném IDE, třeba: PowerGUI PowerShell Analyzer