commands.ps1
<# .SYNOPSIS Clear the imported AX 2012 PowerShell modules .DESCRIPTION Removes the different AX 2012 PowerShell modules that has been loaded into the session. .EXAMPLE PS C:\> Clear-Ax2012StandardPowershellModule This will remove all the known AX 2012 PowerShell modules that have been loaded. It is connected to the use of Import-Module $Script:AxPowerShellModule .NOTES Author: M�tz Jensen (@Splaxi) #> function Clear-Ax2012StandardPowershellModule { [CmdletBinding()] param ( ) Remove-Module @("AxUtilLib", "AxUtilLib.PowerShell", "Microsoft.Dynamics.Administration", "Microsoft.Dynamics.AX.Framework.Management", "Microsoft.Dynamics.ManagementUtilities") } <# .SYNOPSIS Convert HashTable into an array .DESCRIPTION Convert HashTable into an array of Key and Value .PARAMETER InputObject The HashTable object that you want to work against .PARAMETER KeyPrefix The prefix that you want to append to the key of the HashTable The default value is "-" .PARAMETER ValuePrefix The prefix that you want to append to the value of the HashTable The default value is " " .EXAMPLE PS C:\> $params = @{DatabaseServer = "Localhost"; DatabaseName = "MicrosoftDynamicsAx_model"} PS C:\> $arguments = Convert-HashToArgString -Inputs $params This will convert the $params into an array of strings, each with the Key and Value. .NOTES Author: M�tz Jensen (@Splaxi) #> function Convert-HashToArgString { [CmdletBinding()] param ( [HashTable] $InputObject, [string] $KeyPrefix = "-", [string] $ValuePrefix = " " ) $InputObject.Keys | ForEach-Object { "$KeyPrefix$($_)$ValuePrefix`"$($InputObject.Item($_))`""} } <# .SYNOPSIS Convert HashTable into an array .DESCRIPTION Convert HashTable with switches inside into an array of Key:Value .PARAMETER InputObject The HashTable object that you want to work against Shold only contain Key / Vaule, where value is $true or $false .PARAMETER KeyPrefix The prefix that you want to append to the key of the HashTable The default value is "-" .PARAMETER ValuePrefix The prefix that you want to append to the value of the HashTable The default value is ":" .EXAMPLE PS C:\> $params = @{NoPrompt = $true; CreateParents = $false} PS C:\> $arguments = Convert-HashToArgStringSwitch -Inputs $params This will convert the $params into an array of strings, each with the Key:Value. .NOTES Author: M�tz Jensen (@Splaxi) #> function Convert-HashToArgStringSwitch { [CmdletBinding()] [OutputType([System.String])] param ( [HashTable] $InputObject, [string] $KeyPrefix = "-", [string] $ValuePrefix = ":" ) foreach ($key in $InputObject.Keys) { $value = "`${0}" -f $InputObject.Item($key).ToString().ToLower() "$KeyPrefix$($key)$ValuePrefix$($value)" } } <# .SYNOPSIS Get details about an AX 2012 AOS instance .DESCRIPTION Get all the technical details about an AX 2012 AOS instance .PARAMETER RegistryPath Path to the registry for the specific AX 2012 AOS instance .EXAMPLE PS C:\> Get-AxAosInstanceDetails -RegistryPath "HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\Dynamics Server\6.0\01" This will traverse all the details about the first installed AX 2012 AOS instance in the registry. .NOTES Author: M�tz Jensen (@Splaxi) #> function Get-AxAosInstanceDetails { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "")] [CmdletBinding()] param( [string] $RegistryPath ) Write-PSFMessage -Level Verbose -Message "Working against $RegistryPath" -Target $RegistryPath $RegKey = Get-Item -Path $RegistryPath.Replace("HKEY_LOCAL_MACHINE", "HKLM:") $RegOuter = Get-ItemProperty -Path ($RegKey.Name).Replace("HKEY_LOCAL_MACHINE", "HKLM:") $RegInner = Get-ItemProperty -Path (Join-Path $RegKey.Name $RegOuter.Current).Replace("HKEY_LOCAL_MACHINE", "HKLM:") $BuildNumbers = Get-FileVersion -Path $(Join-Path $RegInner.bindir "Ax32Serv.exe") $InstanceDetail = [Ordered]@{} $InstanceDetail.InstanceName = $RegOuter.InstanceName $InstanceDetail.ConfigurationName = $RegOuter.Current $InstanceDetail.BinDirectory = $RegInner.bindir $InstanceDetail.ExecutablePath = Join-Path $RegInner.bindir "Ax32Serv.exe" $InstanceDetail.FileVersion = $BuildNumbers.FileVersion $InstanceDetail.ProductVersion = $BuildNumbers.ProductVersion $InstanceDetail.FileVersionUpdated = $BuildNumbers.FileVersionUpdated $InstanceDetail.ProductVersionUpdated = $BuildNumbers.ProductVersionUpdated $InstanceDetail.DatabaseServer = $RegInner.dbserver $InstanceDetail.DatabaseName = $RegInner.database $InstanceDetail.ModelstoreDatabase = "$($RegInner.database)_model" $InstanceDetail.AosPort = $RegInner.port $InstanceDetail.WsdlPort = $RegInner.WSDLPort $InstanceDetail.NetTcpPort = $RegInner.NetTCPPort $InstanceDetail.RegistryKeyPath = $RegKey.Name $InstanceDetail.InstanceNumber = Split-Path -Path $RegKey.Name -Leaf $InstanceDetail.ComputerName = "$env:computername" [PSCustomObject] $InstanceDetail } <# .SYNOPSIS Get the AX 2012 Client bin directory .DESCRIPTION Get the AX 2012 Client bin directory from the registry .EXAMPLE PS C:\> Get-ClientBinDir This will get the full path for the AX 2012 client bin directory .NOTES Author: M�tz Jensen (@Splaxi) #> function Get-ClientBinDir { [CmdletBinding()] [OutputType('System.String')] param ( ) $RegKey = Get-Item -Path $Script:RegistryClient -ErrorAction SilentlyContinue if(-not ($null -eq $RegKey)) { $RegOuter = Get-ItemProperty -Path $($RegKey.Name.Replace("HKEY_CURRENT_USER", "HKCU:")) $RegInner = Get-ItemProperty -Path (Join-Path $RegKey.Name $RegOuter.Current).Replace("HKEY_CURRENT_USER", "HKCU:") $RegInner.bindir } } <# .SYNOPSIS Clone a hashtable .DESCRIPTION Create a deep clone of a hashtable for you to work on it without updating the original object .PARAMETER InputObject The hashtable you want to clone .EXAMPLE PS C:\> Get-DeepClone -InputObject $HashTable This will clone the $HashTable variable into a new object and return it to you. .NOTES Author: M�tz Jensen (@Splaxi) #> function Get-DeepClone { [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseOutputTypeCorrectly', '')] [CmdletBinding()] param( [parameter(Mandatory = $true)] $InputObject ) process { if ($InputObject -is [hashtable]) { $clone = @{} foreach ($key in $InputObject.keys) { $clone[$key] = Get-DeepClone $InputObject[$key] } $clone } else { $InputObject } } } <# .SYNOPSIS Get the file version details .DESCRIPTION Get the file version details for any given file .PARAMETER Path Path to the file that you want to extract the file version details from .EXAMPLE PS C:\> Get-FileVersion -Path "C:\Program Files\Microsoft Dynamics AX\60\Server\MicrosoftDynamicsAX\Bin\AxServ32.exe" This will get the file version details for the AX AOS executable (AxServ32.exe). .NOTES Author: M�tz Jensen (@Splaxi) Inspired by https://blogs.technet.microsoft.com/askpfeplat/2014/12/07/how-to-correctly-check-file-versions-with-powershell/ #> function Get-FileVersion { [CmdletBinding()] Param( [Parameter(Mandatory = $true)] [string] $Path ) if (-not (Test-PathExists -Path $Path -Type Leaf)) { return } Write-PSFMessage -Level Verbose -Message "Extracting the file properties for: $Path" -Target $Path $Filepath = Get-Item -Path $Path [PSCustomObject]@{ FileVersion = $Filepath.VersionInfo.FileVersion ProductVersion = $Filepath.VersionInfo.ProductVersion FileVersionUpdated = "$($Filepath.VersionInfo.FileMajorPart).$($Filepath.VersionInfo.FileMinorPart).$($Filepath.VersionInfo.FileBuildPart).$($Filepath.VersionInfo.FilePrivatePart)" ProductVersionUpdated = "$($Filepath.VersionInfo.ProductMajorPart).$($Filepath.VersionInfo.ProductMinorPart).$($Filepath.VersionInfo.ProductBuildPart).$($Filepath.VersionInfo.ProductPrivatePart)" } } <# .SYNOPSIS Get key from HashTable .DESCRIPTION Get specific key(s) from a HashTable returned as a HashTable .PARAMETER InputObject The HashTable that you want to extract key(s) from .PARAMETER Keys Names of the key(s) that you want to to extract from the HashTable .EXAMPLE PS C:\> $params = @{NoPrompt = $true; CreateParent = $false} Get-HashtableKey -InputObject $params -Keys "NoPrompt" This will return a new HashTable only containing the "NoPrompt" entry. .NOTES Author: M�tz Jensen (@Splaxi) #> function Get-HashtableKey { [CmdletBinding()] [OutputType([HashTable])] param ( [parameter(Mandatory = $true, Position = 1)] [HashTable] $InputObject, [Parameter(Mandatory = $true, Position = 2)] [string[]] $Keys ) $var = Get-DeepClone $InputObject $res = @{} foreach ($key in $var.Keys) { Write-PSFMessage -Level Verbose -Message "Working on key: $key" -Target $key if($Keys.Contains($key)) { Write-PSFMessage -Level Verbose -Message "Found key: $key" -Target $key $null = $res.Add($key, $var.Item($key)) } } $res } <# .SYNOPSIS Get service list from HashTable .DESCRIPTION Extract the services from the list of entries in the HashTable .PARAMETER AllAxServices Switch to instruct the cmdlet to return all services .PARAMETER Aos Switch to instruct the cmdlet to return AOS .PARAMETER ManagementReporter Switch to instruct the cmdlet to return ManagementReporter .PARAMETER DIXF Switch to instruct the cmdlet to return DIXF .EXAMPLE PS C:\> Get-ServiceList -All This will return all services that the cmdlet knows about. .NOTES Author: M�tz Jensen (@Splaxi) #> Function Get-ServiceList { [CmdletBinding(DefaultParameterSetName = 'Default')] param ( [Parameter(Mandatory = $false, ParameterSetName = 'Default', Position = 1 )] [switch] $AllAxServices, [Parameter(Mandatory = $false, ParameterSetName = 'Specific', Position = 2 )] [switch] $Aos, [Parameter(Mandatory = $false, ParameterSetName = 'Specific', Position = 3 )] [switch] $ManagementReporter, [Parameter(Mandatory = $false, ParameterSetName = 'Specific', Position = 4 )] [switch] $DIXF ) if ($PSCmdlet.ParameterSetName -eq "Specific") { $AllAxServices = $false } Write-PSFMessage -Level Verbose -Message "The PSBoundParameters was" -Target ($PSBoundParameters.Keys -Join "," ) $MRService = "MR2012ProcessService" $dixfname = "Microsoft.Dynamics.AX.Framework.Tools.DMF.SSISHelperService.exe" [System.Collections.ArrayList]$Services = New-Object -TypeName "System.Collections.ArrayList" if ($AllAxServices) { for ($i = 1; $i -lt 100; $i++) { $null = $Services.Add("AOS60`$$($i.ToString("00"))") } $null = $Services.AddRange(@($MRService, $dixfname)) } else { if ($Aos) { for ($i = 1; $i -lt 100; $i++) { $null = $Services.Add("AOS60`$$($i.ToString("00"))") } } if ($ManagementReporter) { $null = $Services.Add($ManagementReporter) } if ($DIXF) { $null = $Services.Add($dixfname) } } $Services.ToArray() } <# .SYNOPSIS Get a SqlCommand object .DESCRIPTION Get a SqlCommand object initialized with the passed parameters .PARAMETER DatabaseServer The name of the database server .PARAMETER DatabaseName The name of the database .PARAMETER SqlUser The login name for the SQL Server instance .PARAMETER SqlPwd The password for the SQL Server user. .PARAMETER TrustedConnection Should the connection use a Trusted Connection or not .EXAMPLE PS C:\> Get-SqlCommand -DatabaseServer localhost -DatabaseName MicrosoftDynamicsAx_model -SqlUser User123 -SqlPwd "Password123" -TrustedConnection $false This will initialize a new SqlCommand object (.NET type) with localhost as the server name, AxDB as the database and the User123 sql credentials. .EXAMPLE PS C:\> Get-SqlCommand -DatabaseServer localhost -DatabaseName MicrosoftDynamicsAx_model -TrustedConnection $true This will initialize a new SqlCommand object (.NET type) with localhost as the server name, AxDB as the database and use the current windows credentials (trusted connection). .NOTES Author: Rasmus Andersen (@ITRasmus) Author: M�tz Jensen (@Splaxi) #> function Get-SQLCommand { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [string] $DatabaseServer, [Parameter(Mandatory = $true)] [string] $DatabaseName, [Parameter(Mandatory = $false)] [string] $SqlUser, [Parameter(Mandatory = $false)] [string] $SqlPwd, [Parameter(Mandatory = $false)] [boolean] $TrustedConnection ) Write-PSFMessage -Level Debug -Message "Writing the bound parameters" -Target $PsBoundParameters [System.Collections.ArrayList]$Params = New-Object -TypeName "System.Collections.ArrayList" $null = $Params.Add("Server='$DatabaseServer';") $null = $Params.Add("Database='$DatabaseName';") if ($null -eq $TrustedConnection -or (-not $TrustedConnection)) { $null = $Params.Add("User='$SqlUser';") $null = $Params.Add("Password='$SqlPwd';") } else { $null = $Params.Add("Integrated Security='SSPI';") } $null = $Params.Add("Application Name='ax2012.tools'") Write-PSFMessage -Level Verbose -Message "Building the SQL connection string." -Target $Params $sqlConnection = New-Object System.Data.SqlClient.SqlConnection try { $sqlConnection.ConnectionString = ($Params -join "") $sqlCommand = New-Object System.Data.SqlClient.SqlCommand $sqlCommand.Connection = $sqlConnection $sqlCommand.CommandTimeout = 0 } catch { Write-PSFMessage -Level Host -Message "Something went wrong while working with the sql server connection objects" -Exception $PSItem.Exception Stop-PSFFunction -Message "Stopping because of errors" return } $sqlCommand } <# .SYNOPSIS Get WMDP details from the IIS .DESCRIPTION Get all the necessary details from the IIS about the WMDP installation .EXAMPLE PS C:\> Get-WMDPDetailsFromIIS This will get details from all the WMDP installations on the server. .NOTES Author: M�tz Jensen (@Splaxi) #> function Get-WMDPDetailsFromIIS { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "")] [CmdletBinding()] param ( ) if ((Get-Module -ListAvailable -Name "IISAdministration").Count -lt 1) { Write-PSFMessage -Level Host -Message "It seems that you didn't have the <c='em'>extended</c> powershell administration tools for IIS installed. For Windows Server 2012 and 2012 R2 it is required that you install this module directly." Write-PSFMessage -Level Host -Message "Install-Module IISAdministration -Force -Confirm:`$false" Stop-PSFFunction -Message "Stopping because of missing parameters" -StepsUpward 1 return } else { $null = Import-Module -name "IISAdministration" -Force } $sites = Get-IISSite | Where-Object {$_.Applications.VirtualDirectories.PhysicalPath -like "*AX*warehouse*portal*"} foreach ($site in $sites) { $res = [Ordered]@{SiteId = $site.Id; SiteName = $site.Name; SiteStatus = $site.State; SiteBindings = $site.Bindings; Path = $site.Applications.VirtualDirectories.PhysicalPath MvcViewPath = Join-Path $site.Applications.VirtualDirectories.PhysicalPath "Views\Execute" CssPath = Join-Path $site.Applications.VirtualDirectories.PhysicalPath "Content\CSS\RFCSS" } $appPool = Get-IISAppPool | Where-Object Name -eq $site.Applications.ApplicationPoolName $res.AppPoolName = $appPool.Name $res.AppPoolStatus = $appPool.Status $res.AppPoolIdentity = $appPool.ProcessModel.Username [PSCustomObject]$res } } <# .SYNOPSIS Invoke timing logic .DESCRIPTION Invoke timing logic that keeps track of the time spend inside a function .PARAMETER Start Switch to instruct the cmdlet that the starting of measurement .PARAMETER End Switch to instruct the cmdlet that the ending of measurement .EXAMPLE PS C:\> Invoke-TimeSignal -Start This will start the timing measurement. .EXAMPLE PS C:\> Invoke-TimeSignal -End This will end the timing measurement and have the cmdlet write the details into the verbose log. .NOTES Author: M�tz Jensen (@Splaxi) #> function Invoke-TimeSignal { [CmdletBinding(DefaultParameterSetName = 'Start')] param ( [Parameter(Mandatory = $true, ParameterSetName = 'Start', Position = 1 )] [switch] $Start, [Parameter(Mandatory = $True, ParameterSetName = 'End', Position = 2 )] [switch] $End ) $Time = (Get-Date) $Command = (Get-PSCallStack)[1].Command if($Start.IsPresent) { if($Script:TimeSignals.ContainsKey($Command)) { Write-PSFMessage -Level Verbose -Message "The command '$Command' was already taking part in time measurement. The entry has been update with current date and time." $Script:TimeSignals[$Command] = $Time } else{ $Script:TimeSignals.Add($Command, $Time) } } else{ if($Script:TimeSignals.ContainsKey($Command)) { $TimeSpan = New-TimeSpan -End $Time -Start (($Script:TimeSignals)[$Command]) Write-PSFMessage -Level Verbose -Message "Total time spent inside the function was $TimeSpan" -Target $TimeSpan -FunctionName $Command -Tag "TimeSignal" $Script:TimeSignals.Remove($Command) } else { Write-PSFMessage -Level Verbose -Message "The command '$Command' was never started to take part in time measurement." } } } <# .SYNOPSIS Create a new folder with datetime in its name .DESCRIPTION Create a new folder with current date and time as part of its name .PARAMETER Path Path to the parent folder where you want the new folder created .PARAMETER NoCreate Switch to instruct the cmdlet not to create the folder .EXAMPLE PS C:\> New-FolderWithDateTime -Path "c:\temp\ax2012.tools" This will create a new folder with the current date and time as a child to the "c:\temp\ax2012.tools" folder. .NOTES Author: M�tz Jensen (@Splaxi) #> Function New-FolderWithDateTime { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "")] [CmdletBinding()] param( [Parameter(Mandatory = $true, Position = 1)] [string] $Path, [Parameter(Mandatory = $false, Position = 2)] [switch] $NoCreate ) $dateString = (Get-Date).ToString("yyyy-MM-dd_HH.mm.ss") $backUpPath = Join-Path $Path $dateString Write-PSFMessage -Level Verbose -Message "Creating the new directory: $backUpPath" -Target $backUpPath if (-not ($NoCreate)) { $null = New-Item -Path $backUpPath -ItemType Directory -Force } $backUpPath } <# .SYNOPSIS Test accessible to the configuration storage .DESCRIPTION Test if the desired configuration storage is accessible with the current user context .PARAMETER ConfigStorageLocation Parameter used to instruct where to store the configuration objects The default value is "User" and this will store all configuration for the active user Valid options are: "User" "System" "System" will store the configuration so all users can access the configuration objects .EXAMPLE PS C:\> Test-ConfigStorageLocation -ConfigStorageLocation "System" This will test if the current executing user has enough privileges to save to the system wide configuration storage. The system wide configuration storage requires administrator rights. .NOTES Author: M�tz Jensen (@Splaxi) #> function Test-ConfigStorageLocation { [CmdletBinding()] [OutputType('System.String')] param ( [ValidateSet('User', 'System')] [string] $ConfigStorageLocation = "User" ) $configScope = "UserDefault" if ($ConfigStorageLocation -eq "System") { if ($Script:IsAdminRuntime) { $configScope = "SystemDefault" } else { Write-PSFMessage -Level Host -Message "Unable to locate save the <c='em'>configuration objects</c> in the <c='em'>system wide configuration store</c> on the machine. Please start an elevated session and run the cmdlet again." Stop-PSFFunction -Message "Elevated permissions needed. Please start an elevated session and run the cmdlet again." -StepsUpward 1 return } } $configScope } <# .SYNOPSIS Test multiple paths .DESCRIPTION Easy way to test multiple paths for public functions and have the same error handling .PARAMETER Path Array of paths you want to test They have to be the same type, either file/leaf or folder/container .PARAMETER Type Type of path you want to test Valid options are: "Leaf" "Container" .PARAMETER Create Switch to instruct the cmdlet to create the folder .EXAMPLE PS C:\> Test-PathExists "c:\temp","c:\temp\dir" -Type Container This will test if the mentioned paths (folders) exists and the current context has enough permission. .NOTES Author: M�tz Jensen (@splaxi) #> function Test-PathExists { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "")] [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "")] [CmdletBinding()] [OutputType([System.Boolean])] param ( [Parameter(Mandatory = $True, Position = 1 )] [string[]] $Path, [ValidateSet('Leaf', 'Container')] [Parameter(Mandatory = $True, Position = 2 )] [string] $Type, [switch] $Create ) $res = $false $arrList = New-Object -TypeName "System.Collections.ArrayList" foreach ($item in $Path) { Write-PSFMessage -Level Verbose -Message "Testing the path: $item" -Target $item $temp = Test-Path -Path $item -Type $Type if ((!$temp) -and ($Create) -and ($Type -eq "Container")) { Write-PSFMessage -Level Verbose -Message "Creating the path: $item" -Target $item New-Item -Path $item -ItemType Directory -Force -ErrorAction Stop $temp = $true } elseif (!$temp) { Write-PSFMessage -Level Host -Message "The <c='em'>$item</c> path wasn't found. Please ensure the path <c='em'>exists</c> and you have enough <c='em'>permission</c> to access the path." } $null = $arrList.Add($temp) } if ($arrList.Contains($false)) { Stop-PSFFunction -Message "Stopping because of missing paths." -StepsUpward 1 } else { $res = $true } $res } <# .SYNOPSIS Test if a given registry key exists or not .DESCRIPTION Test if a given registry key exists in the path specified .PARAMETER Path Path to the registry hive and sub directories you want to work against .PARAMETER Name Name of the registry key that you want to test for .EXAMPLE PS C:\> Test-RegistryValue -Path "HKLM:\SOFTWARE\Microsoft\Dynamics\Deployment\" -Name "InstallationInfoDirectory" This will query the LocalMachine hive and the sub directories "HKLM:\SOFTWARE\Microsoft\Dynamics\Deployment\" for a registry key with the name of "InstallationInfoDirectory". .NOTES Author: M�tz Jensen (@Splaxi) #> Function Test-RegistryValue { [OutputType('System.Boolean')] param( [Parameter(Mandatory = $true)] [string]$Path, [Parameter(Mandatory = $true)] [string]$Name ) if (Test-Path -Path $Path -PathType Any) { $null -ne (Get-ItemProperty $Path).$Name } else { $false } } <# .SYNOPSIS Test PSBoundParameters whether or not to support TrustedConnection .DESCRIPTION Test callers PSBoundParameters (HashTable) for details that determines whether or not a SQL Server connection should support TrustedConnection or not .PARAMETER Inputs HashTable ($PSBoundParameters) with the parameters from the callers invocation .EXAMPLE PS C:\> $UseTrustedConnection = Test-TrustedConnection $PSBoundParameters This will send the entire HashTable from the callers invocation, containing all explicit defined parameters to be analyzed whether or not the SQL Server connection should support TrustedConnection or not. .NOTES Author: M�tz Jensen (@splaxi) #> function Test-TrustedConnection { [CmdletBinding()] [OutputType([System.Boolean])] param ( [HashTable] $Inputs ) if (($Inputs.ContainsKey("SqlUser")) -or ($Inputs.ContainsKey("SqlPwd"))) { Write-PSFMessage -Level Verbose -Message "Not capable of using Trusted Connection based on supplied SQL login details." $false } elseif ($Inputs.ContainsKey("TrustedConnection")) { Write-PSFMessage -Level Verbose -Message "The script was calling with TrustedConnection directly. This overrides all other logic in respect that the caller should know what it is doing. Value was: $($Inputs.TrustedConnection)" -Tag $Inputs.TrustedConnection $Inputs.TrustedConnection } else { $false } } <# .SYNOPSIS Export an AX 2012 modelstore file .DESCRIPTION Export an AX 2012 modelstore file from the modelstore database .PARAMETER DatabaseServer Server name of the database server Default value is: "localhost" .PARAMETER ModelstoreDatabase Name of the modelstore database Default value is: "MicrosoftDynamicsAx_model" Note: From AX 2012 R2 and upwards you need to provide the full name for the modelstore database. E.g. "AX2012R3_PROD_model" .PARAMETER InstanceName Name of the instance that you are working against If not supplied the cmdlet will take the name of the database and use that .PARAMETER Suffix A suffix text value that you want to add to the name of the file while it is exported The default value is: (Get-Date).ToString("yyyyMMdd") This will always name you file with the current date .PARAMETER Path Path to the location where you want the file to be exported Default value is: "c:\temp\ax2012.tools" .PARAMETER GenerateScript Switch to instruct the cmdlet to only generate the needed command and not execute it .EXAMPLE PS C:\> Invoke-AxExportModelstore This will execute the cmdlet with all the default values. This will work against the SQL server that is on localhost. The database is expected to be "MicrosoftDynamicsAx_model". The path where the exported modelstore file will be saved is: "c:\temp\ax2012.tools". .NOTES Author: M�tz Jensen (@Splaxi) #> Function Export-AxModelStoreV2 { [CmdletBinding()] [OutputType('System.String')] Param( [string] $DatabaseServer = $Script:ActiveAosDatabaseserver, [string] $ModelstoreDatabase = $Script:ActiveAosModelstoredatabase, [string] $InstanceName = $Script:ActiveAosInstancename, [string] $Suffix = $((Get-Date).ToString("yyyyMMdd")), [string] $Path = $Script:DefaultTempPath, [switch] $GenerateScript ) Invoke-TimeSignal -Start if (-not (Test-PathExists -Path $Path -Type Container -Create)) { return } if (-not (Test-PathExists -Path $Script:AxPowerShellModule -Type Leaf)) { return } if ([System.String]::IsNullOrEmpty($InstanceName)) { $InstanceName = "{0}" -f $ModelstoreDatabase.Replace("_model", "") } if (-not ([system.string]::IsNullOrEmpty($Suffix))) { $ExportPath = Join-Path $Path "$($InstanceName)_$($Suffix).axmodelstore" } else { $ExportPath = Join-Path $Path "$InstanceName.axmodelstore" } $params = @{ Server = $DatabaseServer Database = $ModelstoreDatabase File = $ExportPath } if ($GenerateScript) { $arguments = Convert-HashToArgString -InputObject $params "Export-AxModelStore $($arguments -join ' ')" } else { Write-PSFMessage -Level Verbose -Message "Starting the export of the model store" $null = Import-Module $Script:AxPowerShellModule Export-AxModelStore @params Clear-Ax2012StandardPowershellModule } Invoke-TimeSignal -End } @("AxUtilLib", "AxUtilLib.PowerShell", "Microsoft.Dynamics.Administration", "Microsoft.Dynamics.AX.Framework.Management", "Microsoft.Dynamics.ManagementUtilities") <# .SYNOPSIS Export AX 2012 model .DESCRIPTION Export AX 2012 model from the AX 2012 model store .PARAMETER DatabaseServer Server name of the database server Default value is: "localhost" .PARAMETER ModelstoreDatabase Name of the modelstore database Default value is: "MicrosoftDynamicsAx_model" Note: From AX 2012 R2 and upwards you need to provide the full name for the modelstore database. E.g. "AX2012R3_PROD_model" .PARAMETER Path Path to the location where you want the file to be exported Default value is: "c:\temp\ax2012.tools" .PARAMETER Name Name of the AX 2012 model that you are looking for Accepts wildcards for searching. E.g. -Name "ISV*MODULE*" Default value is "*" which will search for all models .PARAMETER Id Id of the AX 2012 model that you are looking for Accepts wildcards for searching. E.g. -Id "2*" Default value is "*" which will search for all models .PARAMETER Layer Layer where the AX 2012 model that you are looking for should reside Accepts wildcards for searching. E.g. -Layer "IS*" Default value is "*" which will search for models in all layers .PARAMETER GenerateScript Switch to instruct the cmdlet to output the script to execute the command in hand .EXAMPLE PS C:\> Get-AxAosInstance | Export-AxModelV2 This will fetch all the AX 2012 AOS instances that are configured on the machine. Foreach of the instances it will export all AX 2012 Models into a sub folder to "c:\temp\ax2012.tools". .EXAMPLE PS C:\> Export-AxModelV2 -DatabaseServer localhost -ModelstoreDatabase MicrosoftDynamicsAx_model -Name *CUS* This will fetch all the AX 2012 AOS instances that are configured on the machine. Foreach of the instances it will export all AX 2012 Models into a sub folder to "c:\temp\ax2012.tools". .NOTES Author: M�tz Jensen (@Splaxi) #> Function Export-AxModelV2 { [CmdletBinding()] [OutputType([System.String], ParameterSetName="Generate")] Param( [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 1)] [string] $DatabaseServer = $Script:ActiveAosDatabaseserver, [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 2)] [string] $ModelstoreDatabase = $Script:ActiveAosModelstoredatabase, [Parameter(Mandatory = $false, Position = 3)] [string] $Path = $Script:DefaultTempPath, [Parameter(Mandatory = $false, Position = 4)] [string] $Name = "*", [Parameter(Mandatory = $false, Position = 5)] [string] $Id = "*", [Parameter(Mandatory = $false, Position = 6)] [string] $Layer = "*", [Parameter(ParameterSetName = "Generate")] [switch] $GenerateScript ) BEGIN { if (-not ($GenerateScript)) { if (-not (Test-PathExists -Path $Path -Type Container -Create)) { return } $backupFilePath = New-FolderWithDateTime -Path $Path } else { $backupFilePath = New-FolderWithDateTime -Path $Path -NoCreate } $null = Import-Module $Script:AxPowerShellModule } PROCESS { Invoke-TimeSignal -Start $xml = (Get-AXModel -Server $DatabaseServer -Database $ModelstoreDatabase | ConvertTo-Xml ) $nodes = $xml.SelectNodes("Objects/Object") foreach ($obj in $nodes) { $filenameAxModel = "" $modelId = "" $modelLayer = "" $modelName = "" # Loop all properties foreach ($property in $obj.SelectNodes("Property")) { if ($property.GetAttribute("Name").Equals( "Name" )) { $modelName = $property.InnerText } if ($property.GetAttribute("Name").Equals( "Layer" )) { $modelLayer = $property.InnerText } if ($property.GetAttribute("Name").Equals( "ModelId" )) { $modelId = $property.InnerText } } $filenameAxModel = $modelId + "_" + $modelName + ".axmodel" Write-PSFMessage -Level Verbose -Message "Testing that ModelName, ModelId and Layer matches the search criteria" if ($modelName -NotLike $Name) { continue } if ($modelId -NotLike $Id) { continue } if ($modelLayer -NotLike $Layer) { continue } if ($Script:LayerDictionary.ContainsKey($modelLayer.ToUpper()) -and $filenameAxModel -ne "") { $localLayer = $Script:LayerDictionary.Get_Item($modelLayer.ToUpper()) + $modelLayer.ToUpper() $tempPath = Join-Path $backupFilePath $localLayer $filenameAxModel = Join-Path $tempPath $filenameAxModel $params = @{Model = $modelName; File = $filenameAxModel; Server = $DatabaseServer; Database = $ModelstoreDatabase } if ($GenerateScript) { $arguments = Convert-HashToArgString -InputObject $params "Export-AXModel $($arguments -join ' ')" } else { if (-not (Test-PathExists -Path $tempPath -Type Container -Create)) { return } Write-PSFMessage -Level Verbose -Message "Starting the export of the ax model file" $null = Export-AXModel @params } } else { Write-PSFMessage -Level Verbose -Message "Skipping $filenameAxModel in layer $modelLayer" } } Invoke-TimeSignal -End } END { if (-not ($GenerateScript)) { [PSCustomObject]@{ Path = $backupFilePath } } Clear-Ax2012StandardPowershellModule } } <# .SYNOPSIS Get the active stored AX 2012 AOS configuration .DESCRIPTION Get the active AX 2012 AOS configuration from the configuration storage .EXAMPLE PS C:\> Get-AxActiveAosConfiguration This will export all the stored details saved into the configuration storage. .NOTES Author: M�tz Jensen (@Splaxi) #> function Get-AxActiveAosConfiguration { [CmdletBinding()] param ( ) $res = [Ordered]@{} $res.InstanceName = Get-PSFConfigValue -FullName 'ax2012.tools.active.aos.instancename' $res.BinDirectory = Get-PSFConfigValue -FullName 'ax2012.tools.active.aos.bindirectory' $res.DatabaseServer = Get-PSFConfigValue -FullName 'ax2012.tools.active.aos.databaseserver' $res.DatabaseName = Get-PSFConfigValue -FullName 'ax2012.tools.active.aos.database' $res.ModelstoreDatabase = Get-PSFConfigValue -FullName 'ax2012.tools.active.aos.modelstoredatabase' $res.AosPort = Get-PSFConfigValue -FullName 'ax2012.tools.active.aos.aos.port' $res.WsdlPort = Get-PSFConfigValue -FullName 'ax2012.tools.active.aos.wsdl.port' $res.NetTcpPort = Get-PSFConfigValue -FullName 'ax2012.tools.active.aos.nettcp.port' $res.InstanceNumber = Get-PSFConfigValue -FullName 'ax2012.tools.active.aos.instance.number' $res.ComputerName = Get-PSFConfigValue -FullName 'ax2012.tools.active.aos.computername' [PSCustomObject] $res } <# .SYNOPSIS Get AX 2012 AOS Instance .DESCRIPTION Get AX 2012 AOS Instance details from the local machine .PARAMETER Name The search string to filter the AOS instance that you're looking for The parameter supports wildcards. E.g. -Name "*DEV*" Default value is "*" and will give you all the instances .PARAMETER InstanceNo The search string to filter the AOS instance that you're looking for The parameter supports wildcards. E.g. -InstanceNo "*1*" Default value is "*" and will give you all the instances .EXAMPLE PS C:\> Get-AxAosInstance This will get you all the installed AX 2012 AOS instances on the machine .NOTES Author: M�tz Jensen (@Splaxi) #> function Get-AxAosInstance { [CmdletBinding()] Param( [Parameter()] [string] $Name = "*", [Parameter()] [string] $InstanceNo = "*" ) $Instances = Get-ChildItem -Path $Script:RegistryAos $res = New-Object System.Collections.ArrayList $Instances | ForEach-Object { $null = $res.Add((Get-AxAosInstanceDetails $_.Name)) } foreach ($obj in $res) { if ($obj.InstanceName -NotLike $Name) { continue } if ($obj.InstanceNumber -NotLike $InstanceNo) { continue } $obj } } <# .SYNOPSIS Get the build numbers .DESCRIPTION Get the build numbers for the AX 2012 client .PARAMETER Path The path to the Ax32.exe file you want to work against The default path is read from the registry .EXAMPLE PS C:\> Get-AxClientBuild This will get the executable path and the build numbers for the client. .NOTES Author: M�tz Jensen (@Splaxi) #> function Get-AxClientBuild { [CmdletBinding()] Param( [string] $Path = $(Join-Path $Script:ClientBin "Ax32.exe") ) $BuildNumbers = Get-FileVersion -Path $Path $clientDetails = [Ordered]@{} $clientDetails.ExecutablePath = $Path $clientDetails.FileVersion = $BuildNumbers.FileVersion $clientDetails.ProductVersion = $BuildNumbers.ProductVersion $clientDetails.FileVersionUpdated = $BuildNumbers.FileVersionUpdated $clientDetails.ProductVersionUpdated = $BuildNumbers.ProductVersionUpdated [PSCustomObject] $clientDetails } <# .SYNOPSIS Get the AX 2012 client configuration .DESCRIPTION Get the AX 2012 client configuration from the registry .PARAMETER Name Name of the configuration that you are looking for The parameter supports wildcards. E.g. -Name "*DEV*" .EXAMPLE PS C:\> Get-AxClientConfig This will get all available client configurations from the registry and display them. .NOTES Author: M�tz Jensen (@Splaxi) #> function Get-AxClientConfig { [CmdletBinding()] Param( [Parameter()] [SupportsWildcards()] [string] $Name = "*" ) $configs = Get-ChildItem -Path $Script:RegistryClient foreach ($item in $configs) { $RegistryPath = Get-Item -Path $($item.Name.Replace("HKEY_CURRENT_USER", "HKCU:")) $configName = Split-Path -Path $RegistryPath.Name -Leaf if ($configName -NotLike $Name) { continue } $RegInner = Get-ItemProperty -Path $($RegistryPath.Name.Replace("HKEY_CURRENT_USER", "HKCU:")) $res = [Ordered]@{ConfigName = $configName} $res.AosServer = ($RegInner.Aos2).Split(":")[0] $res.AosPort = ($RegInner.Aos2).Split(":")[1] if ($RegInner.Aos2 -like "*@*") { $res.InstanceName = ($RegInner.Aos2).Split("@")[0] } $res.AosTrafficEncrypted = $RegInner.AosEncryption $res.BinDir = $RegInner.BinDir $res.ClientDirectory = $RegInner.Directory $res.Aol = $RegInner.Aol $res.AolCode = $RegInner.AolCode [PSCustomObject]$res } } <# .SYNOPSIS Get the status of an AX 2012 environment .DESCRIPTION Get the status of AX 2012 services in your environment .PARAMETER ComputerName Name of the computer(s) that you want to work against .PARAMETER AllAxServices Switch to instruct the cmdlet to include all known AX 2012 services .PARAMETER AosInstanceName Name of the AOS instance that you are looking for Accepts wildcards for searching. E.g. -AosInstanceName "*DEV*" If AxActiveAosConfiguration has been configured, the default value is the name of the instance registered Default value is otherwise "*" which will search for all AOS instances .PARAMETER Aos Switch to instruct the cmdlet to include the AOS service .PARAMETER ManagementReporter Switch to instruct the cmdlet to include the ManagementReporter service .PARAMETER DIXF Switch to instruct the cmdlet to include the DIXF service .PARAMETER ScanAllAosServices Parameter description .EXAMPLE PS C:\> Get-AxEnvironment This will get the status for all the default services from your environment. If AxActiveAosConfiguration has been configured, it will work against the ComputerName and AosInstanceName registered. .EXAMPLE PS C:\> Get-AxEnvironment -ScanAllAosServices This will scan for all available AOS Services. If AxActiveAosConfiguration has been configured, it will work against the ComputerName registered otherwise localhost is used. .EXAMPLE PS C:\> Get-AxEnvironment -ComputerName TEST-AOS-01 -Aos This will get all AOS instances from the server named "TEST-AOS-01". If AxActiveAosConfiguration has been configured, it will work against the AosInstanceName registered otherwise it will find all. .EXAMPLE PS C:\> Get-AxEnvironment -ComputerName TEST-AOS-01 -Aos -AosInstanceName *DEV* This will get all AOS instances that match the search pattern "*DEV*" from the server named "TEST-AOS-01". .EXAMPLE PS C:\> Get-AxEnvironment -ComputerName TEST-AOS-01 -Aos | Start-AxEnvironment -ShowOutput This will scan the "TEST-AOS-01" server for all AOS instances and start them. It will show the status for the service(s) on the server afterwards. .EXAMPLE PS C:\> Get-AxEnvironment -ComputerName TEST-AOS-01 -Aos | Stop-AxEnvironment -ShowOutput This will scan the "TEST-AOS-01" server for all AOS instances and stop them. It will show the status for the service(s) on the server afterwards. .NOTES Author: M�tz Jensen (@Splaxi) #> function Get-AxEnvironment { [CmdletBinding(DefaultParameterSetName = 'Default')] param ( [Alias('Server')] [string[]] $ComputerName = $Script:ActiveAosComputername, [Parameter(Mandatory = $false, ParameterSetName = 'Default', Position = 2 )] [switch] $AllAxServices = [switch]::Present, [Alias('InstanceName')] [string] $AosInstanceName = $(if (-not ([System.String]::IsNullOrEmpty($Script:ActiveAosInstancename))) { "*$Script:ActiveAosInstancename" } else { "*" }), [Parameter(Mandatory = $false, ParameterSetName = 'Specific', Position = 2 )] [switch] $Aos, [Parameter(Mandatory = $false, ParameterSetName = 'Specific', Position = 3 )] [switch] $ManagementReporter, [Parameter(Mandatory = $false, ParameterSetName = 'Specific', Position = 4 )] [switch] $DIXF, [switch] $ScanAllAosServices ) if ($PSCmdlet.ParameterSetName -eq "Specific") { $AllAxServices = ![switch]::Present } if (!$AllAxServices -and !$Aos -and !$ManagementReporter -and !$DIXF) { Write-PSFMessage -Level Host -Message "You have to use at least one switch when running this cmdlet. Please run the cmdlet again." Stop-PSFFunction -Message "Stopping because of missing parameters" return } $baseParams = Get-DeepClone $PSBoundParameters $params = @{} $includeParamNames = @("ManagementReporter", "DIXF") foreach ($key in $baseParams.Keys) { Write-PSFMessage -Level Verbose -Message "Working on key: $key" -Target $key if ($includeParamNames -notlike $key ) {continue} $null = $params.Add($key, $baseParams.Item($key).ToString()) } if ($params.Count -eq 0) { if ($AllAxServices) { $params.AllAxServices = $true $Services = Get-ServiceList @params } } else { $Services = Get-ServiceList @params } if ($PSBoundParameters.ContainsKey("Aos")) { Write-PSFMessage -Level Verbose -Message "Aos seems to be bound" -Target $key $searchServicesAos = Get-ServiceList -Aos } $res = New-Object System.Collections.ArrayList foreach ($server in $ComputerName) { Write-PSFMessage -Level Verbose -Message "Working against: $server - listing services" -Target ($Services -Join ",") Write-PSFMessage -Level Verbose -Message "Working against: $server - listing Aos services" -Target ($searchServicesAos -Join ",") if (-not ($null -eq $searchServicesAos)) { $colAosServices = Get-Service -ComputerName $server -Name $searchServicesAos -ErrorAction SilentlyContinue | Select-Object @{Name = "Server"; Expression = {$Server}}, Name, Status, DisplayName foreach ($service in $colAosServices) { if ((-not $ScanAllAosServices) -and ($service.DisplayName -NotLike $AosInstanceName)) { continue } $null = $res.Add($service) } } if (-not ($null -eq $Services)) { $axServices = Get-Service -ComputerName $server -Name $Services -ErrorAction SilentlyContinue | Select-Object @{Name = "Server"; Expression = {$Server}}, Name, Status, DisplayName foreach ($service in $axServices) { if ($service.DisplayName -like "*AX Object Server*" ) { if ((-not $ScanAllAosServices) -and ($service.DisplayName -NotLike $AosInstanceName)) { continue } } $null = $res.Add($service) } } } $res.ToArray() | Select-Object Server, DisplayName, Status, Name } <# .SYNOPSIS Get WMDP details .DESCRIPTION Get the most relevant WMDP details from your AX 2012 environment .EXAMPLE PS C:\> Get-AxWMDPDetails This will get all the relevant WMDP details from the AX 2012 environment .NOTES Author: M�tz Jensen (@Splaxi) #> function Get-AxWMDPDetails { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "")] [CmdletBinding()] param ( ) Get-WMDPDetailsFromIIS } <# .SYNOPSIS Import an AX 2012 modelstore file .DESCRIPTION Import an AX 2012 modelstore file into the modelstore database .PARAMETER DatabaseServer Server name of the database server Default value is: "localhost" .PARAMETER ModelstoreDatabase Name of the modelstore database Default value is: "MicrosoftDynamicsAx_model" Note: From AX 2012 R2 and upwards you need to provide the full name for the modelstore database. E.g. "AX2012R3_PROD_model" .PARAMETER SchemaName Name of the schema to import the modelstore into Default value is: "TempSchema" .PARAMETER Path Path to the location where you want the file to be exported Default value is: "c:\temp\ax2012.tools" .PARAMETER IdConflictMode Parameter to instruct how the import should handle ID conflicts if it hits any during the import Valid options: "Reject" "Push" "Overwrite" .PARAMETER Apply Switch to instruct the cmdlet to switch modelstore with the SchemaName in as the current code .PARAMETER GenerateScript Switch to instruct the cmdlet to only generate the needed command and not execute it .EXAMPLE PS C:\> Invoke-AxImportModelstore -SchemaName TempSchema -Path C:\Temp\ax2012.tools\MicrosoftDynamicsAx.axmodelstore This will execute the cmdlet with some of the default values. This will work against the SQL server that is on localhost. The database is expected to be "MicrosoftDynamicsAx_model". The import will import the modelstore into the "TempSchema". The path where the modelstore file you want to import must exists is: "c:\temp\ax2012.tools\MicrosoftDynamicsAx.axmodelstore". .NOTES Author: M�tz Jensen (@Splaxi) #> function Import-AXModelStoreV2 { [CmdletBinding(DefaultParameterSetName = "ImportModelstore")] [OutputType([System.String], ParameterSetName = "Generate")] Param( [string] $DatabaseServer = $Script:ActiveAosDatabaseserver, [string] $ModelstoreDatabase = $Script:ActiveAosModelstoredatabase, [Parameter(ParameterSetName = "ImportModelstore")] [Parameter(ParameterSetName = "ApplyModelstore")] [string] $SchemaName = "TempSchema", [Parameter(ParameterSetName = "ImportModelstore")] [string] $Path = (Join-Path $Script:DefaultTempPath "MicrosoftDynamicsAx.axmodelstore"), [ValidateSet("Reject", "Push", "Overwrite")] [Parameter(ParameterSetName = "ImportModelstore")] [string] $IdConflictMode, [Parameter(ParameterSetName = "ApplyModelstore")] [switch] $Apply, [switch] $GenerateScript ) Invoke-TimeSignal -Start if (-not (Test-PathExists -Path $Path -Type Container -Create)) { return } if (-not (Test-PathExists -Path $Script:AxPowerShellModule -Type Leaf)) { return } $params = @{ Server = $DatabaseServer Database = $ModelstoreDatabase } if ($PSCmdlet.ParameterSetName -eq "ImportModelstore") { $params.File = $Path $params.SchemaName = $SchemaName if ($PSBoundParameters.ContainsKey("IdConflictMode")) { $params.IdConflict = $IdConflictMode } } elseif ($PSCmdlet.ParameterSetName -eq "ApplyModelstore") { $params.Apply = $SchemaName } if ($GenerateScript) { $arguments = Convert-HashToArgString -InputObject $params "Import-AxModelStore $($arguments -join ' ')" } else { Write-PSFMessage -Level Verbose -Message "Starting the export of the model store" $null = Import-Module $Script:AxPowerShellModule Import-AXModelStore @params Clear-Ax2012StandardPowershellModule } Invoke-TimeSignal -End } <# .SYNOPSIS Import AX 2012 model .DESCRIPTION Import AX 2012 model into the AX 2012 Model store .PARAMETER DatabaseServer Server name of the database server Default value is: "localhost" .PARAMETER ModelstoreDatabase Name of the modelstore database Default value is: "MicrosoftDynamicsAx_model" Note: From AX 2012 R2 and upwards you need to provide the full name for the modelstore database. E.g. "AX2012R3_PROD_model" .PARAMETER Path Path to the folder containing the AX model file(s) that you want to import The cmdlet will traverse all sub folders for files and import them based on their names .PARAMETER ConflictMode Instructs the cmdlet to handle conflicts The list of options is: "Reject" "Push" "Overwrite" .PARAMETER CreateParents Switch to instruct the cmdlet to create missing parents on import .PARAMETER NoOptimize Switch to instruct the cmdlet to skip the optimization on import This makes sense if you are import more than 1-2 AX 2012 models at the same time .PARAMETER NoPrompt Switch to instruct the cmdlet not to prompt you with anything .PARAMETER GenerateScript Switch to instruct the cmdlet to output a script that you can execute manually later Using this will not import any AX 2012 models into the model store .EXAMPLE PS C:\> Import-AxModelV2 -Path "c:\temp\ax2012.tools\dev-models" The cmdlet will look for all the AX 2012 models located in "c:\temp\ax2012.tools\dev-models" or any of its sub folders. The ConflictMode is set to the default value of "OverWrite". The Database Server is set to the default value of "localhost". The Modelstore Database is set to the default value of "MicrosoftDynamicsAx_model". .NOTES Author: M�tz Jensen (@Splaxi) #> Function Import-AxModelV2 { [CmdletBinding()] [OutputType([System.String], ParameterSetName="Generate")] Param( [Parameter(ValueFromPipelineByPropertyName, Mandatory = $false, ValueFromPipeline = $true, Position = 1)] [string] $DatabaseServer = $Script:ActiveAosDatabaseserver, [Parameter(ValueFromPipelineByPropertyName, Mandatory = $false, ValueFromPipeline = $true, Position = 2)] [string] $ModelstoreDatabase = $Script:ActiveAosModelstoredatabase, [Parameter(Mandatory = $false, Position = 3)] [string] $Path = $Script:DefaultTempPath, [Parameter(Mandatory = $false, Position = 4)] [ValidateSet("Reject", "Push", "Overwrite")] [string] $ConflictMode = "Overwrite", [switch] $CreateParents, [switch] $NoOptimize, [switch] $NoPrompt, [Parameter(ParameterSetName = "Generate")] [switch] $GenerateScript ) BEGIN { $null = Import-Module $Script:AxPowerShellModule if (-not (Test-PathExists -Path $Path -Type Container)) { return } } PROCESS { if (Test-PSFFunctionInterrupt) { return } Invoke-TimeSignal -Start $AxModelsPath = (Get-ChildItem -Path $Path | Where-Object {$_.PSIsContainer} | Sort-Object CreationTime -Descending | Select-Object -First 1 | Select-Object Fullname).FullName Write-PSFMessage -Level Verbose -Message "The newest / latest folder is: $AxModelsPath" -Target $AxModelsPath $AxModelFiles = Get-ChildItem -Path $AxModelsPath -Recurse -File $params = @{ Server = $DatabaseServer; Conflict = $ConflictMode; Database = $ModelstoreDatabase } $paramsSwitch = Get-HashtableKey -InputObject $PSBoundParameters -Keys @("CreateParents", "NoOptimize", "NoPrompt") foreach ($item in $AxModelFiles) { Write-PSFMessage -Level Verbose -Message "Working on file: $($item.FullName)" -Target $item.FullName $clonedParams = Get-DeepClone $params $clonedParams += @{ File = $item.FullName } if ($GenerateScript) { $arguments = Convert-HashToArgString -InputObject $clonedParams $argumentsSwitch = Convert-HashToArgStringSwitch -InputObject $paramsSwitch "Install-AxModel $($arguments -join ' ') $($argumentsSwitch -join ' ')" } else { #Install-AXModel @clonedParams @paramsSwitch } } Invoke-TimeSignal -End } END { Clear-Ax2012StandardPowershellModule } } <# .SYNOPSIS Initialize an AX 2012 modelstore .DESCRIPTION Initialize an AX 2012 modelstore against a modelstore database .PARAMETER DatabaseServer Server name of the database server Default value is: "localhost" .PARAMETER ModelstoreDatabase Name of the modelstore database Default value is: "MicrosoftDynamicsAx_model" Note: From AX 2012 R2 and upwards you need to provide the full name for the modelstore database. E.g. "AX2012R3_PROD_model" .PARAMETER SchemaName Name of the schema in the modelstore database that you want to work against Default value is: "TempSchema" .PARAMETER DropSchema Switch to instruct the cmdlet to drop the schema supplied with the -SchemaName parameter .PARAMETER CreateSchema Switch to instruct the cmdlet to create the schema supplied with the -SchemaName parameter .PARAMETER CreateDb Switch to instruct the cmdlet to create a new modelstore inside the supplied -ModelstoreDatabase parameter .PARAMETER GenerateScript Switch to instruct the cmdlet to only generate the needed command and not execute it .EXAMPLE PS C:\> Initialize-AXModelStoreV2 -SchemaName TempSchema -CreateSchema This will execute the cmdlet with some of the default values. This will work against the SQL server that is on localhost. The database is expected to be "MicrosoftDynamicsAx_model". The cmdlet will create the "TempSchema" schema inside the modelstore database. .EXAMPLE PS C:\> Initialize-AXModelStoreV2 -SchemaName TempSchema -DropSchema This will execute the cmdlet with some of the default values. This will work against the SQL server that is on localhost. The database is expected to be "MicrosoftDynamicsAx_model". The cmdlet will drop the "TempSchema" schema inside the modelstore database. .NOTES Author: M�tz Jensen (@Splaxi) #> function Initialize-AXModelStoreV2 { [CmdletBinding(DefaultParameterSetName = "CreateSchema")] [OutputType('System.String')] param ( [string] $DatabaseServer = $Script:ActiveAosDatabaseserver, [string] $ModelstoreDatabase = $Script:ActiveAosModelstoredatabase, [Parameter(ParameterSetName = "Drop")] [Parameter(ParameterSetName = "CreateSchema")] [string] $SchemaName = "TempSchema", [Parameter(ParameterSetName = "Drop")] [switch] $DropSchema, [Parameter(ParameterSetName = "CreateSchema")] [switch] $CreateSchema, [Parameter(ParameterSetName = "CreateDB")] [switch] $CreateDb, [switch] $GenerateScript ) Invoke-TimeSignal -Start if (-not (Test-PathExists -Path $Script:AxPowerShellModule -Type Leaf)) { return } $params = @{ Server = $DatabaseServer Database = $ModelstoreDatabase } if ($PSCmdlet.ParameterSetName -eq "CreateSchema") { $params.SchemaName = $SchemaName } elseif ($PSCmdlet.ParameterSetName -eq "Drop") { $params.Drop = $SchemaName } elseif ($PSCmdlet.ParameterSetName -eq "CreateDB") { $params.CreateDB = $true } if ($GenerateScript) { $arguments = Convert-HashToArgString -InputObject $params "Initialize-AXModelStore $($arguments -join ' ')" } else { Write-PSFMessage -Level Verbose -Message "Starting the initialization of the model store" $null = Import-Module $Script:AxPowerShellModule Initialize-AXModelStore @params Clear-Ax2012StandardPowershellModule } Invoke-TimeSignal -End } <# .SYNOPSIS Aaaaa aaa a aaa a a aa .DESCRIPTION Bbbb b b b b bbbbb bbbb .PARAMETER Path Cccc ccccc ccc cc cc .EXAMPLE PS C:\> Invoke-AxBuild This will work .NOTES Author: M�tz Jensen (@Splaxi) #> function Invoke-AxBuild { [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseOutputTypeCorrectly', '')] [CmdletBinding()] param ( [string] $Path = $Script:ActiveAosBindirectory <# ActiveAosAosPort ActiveAosBindirectory ActiveAosComputername ActiveAosDatabase ActiveAosDatabaseserver ActiveAosInstancename ActiveAosInstanceNumber ActiveAosModelstoredatabase ActiveAosNettcpPort ActiveAosWsdlPort #> ) Get-Variable } <# .SYNOPSIS Set the active AX 2012 AOS configuration .DESCRIPTION Set the active AX 2012 AOS details and store it into the configuration storage .PARAMETER ComputerName The name of the computer / server that AOS resides on .PARAMETER BinDirectory The full path to the bin directory where the AOS instance is physical installed .PARAMETER InstanceNumber The 2 digit ([0-9][0-9]) number that the AOS instance has on the server .PARAMETER InstanceName The instance name the AOS server is registered with .PARAMETER DatabaseServer The name of the server running SQL Server .PARAMETER DatabaseName The name of the AX 2012 business data database .PARAMETER ModelstoreDatabase The name of the AX 2012 modelstore database .PARAMETER AosPort The TCP port that the AX 2012 AOS server is communicating with the AX clients on .PARAMETER WsdlPort The TCP port that the AX 2012 AOS server is communicating with all WSDL consuming applications on .PARAMETER NetTcpPort The TCP port that the AX 2012 AOS server is communicating with all NetTcp consuming applications on .PARAMETER ConfigStorageLocation Parameter used to instruct where to store the configuration objects The default value is "User" and this will store all configuration for the active user Valid options are: "User" "System" "System" will store the configuration so all users can access the configuration objects .PARAMETER Temporary Switch to instruct the cmdlet to only temporarily override the persisted settings in the configuration storage .EXAMPLE PS C:\> Get-AxAosInstance | Select-Object -First 1 | Set-AxActiveAosConfiguration This will get all the AX 2012 AOS instances from the local machine and only select the first output. The output from the first AOS instance is saved into the configuration store. .EXAMPLE PS C:\> Set-AxActiveAosConfiguration -ComputerName AX2012PROD -DatabaseServer SQLSERVER -DatabaseName AX2012R3_PROD -ModelstoreDatabase AX2012R3_PROD_model -AosPort 2712 This will update the active AOS configuration store settings. The computer name will be registered to: AX2012PROD The database server will be registered to: SQLSERVER The database name will be registered to: AX2012R3_PROD The model store database will be registered to: AX2012R3_PROD_model The AOS port will be registered to: 2712 .NOTES Author: M�tz Jensen (@Splaxi) #> function Set-AxActiveAosConfiguration { [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '')] [CmdletBinding()] param ( [Parameter(ValueFromPipelineByPropertyName = $true, Position = 1)] [string[]] $ComputerName = @($env:computername), [Parameter(ValueFromPipelineByPropertyName = $true, Position = 2)] [string] $BinDirectory, [Parameter(ValueFromPipelineByPropertyName = $true, Position = 3)] [string] $InstanceNumber, [Parameter(ValueFromPipelineByPropertyName = $true, Position = 4)] [string] $InstanceName, [Parameter(ValueFromPipelineByPropertyName = $true, Position = 5)] [string] $DatabaseServer, [Parameter(ValueFromPipelineByPropertyName = $true, Position = 6)] [string] $DatabaseName, [Parameter(ValueFromPipelineByPropertyName = $true, Position = 7)] [string] $ModelstoreDatabase, [Parameter(ValueFromPipelineByPropertyName = $true, Position = 8)] [string] $AosPort, [Parameter(ValueFromPipelineByPropertyName = $true, Position = 9)] [string] $WsdlPort, [Parameter(ValueFromPipelineByPropertyName = $true, Position = 10)] [string] $NetTcpPort, [ValidateSet('User', 'System')] [string] $ConfigStorageLocation = "User", [switch] $Temporary ) $configScope = Test-ConfigStorageLocation -ConfigStorageLocation $ConfigStorageLocation if (Test-PSFFunctionInterrupt) { return } foreach ($key in $PSBoundParameters.Keys) { $value = $PSBoundParameters.Item($key) Write-PSFMessage -Level Verbose -Message "Working on $key with $value" -Target $value switch ($key) { "ComputerName" { Set-PSFConfig -Module 'ax2012.tools' -Name 'active.aos.computername' -Value $value $Script:ActiveAosComputername = $value if(-not $Temporary) { Register-PSFConfig -Module 'ax2012.tools' -Name 'active.aos.computername' -Scope $configScope } } "BinDirectory" { Set-PSFConfig -Module 'ax2012.tools' -Name 'active.aos.bindirectory' -Value $value if(-not $Temporary) { Register-PSFConfig -Module 'ax2012.tools' -Name 'active.aos.bindirectory' -Scope $configScope } } "InstanceNumber" { Set-PSFConfig -Module 'ax2012.tools' -Name 'active.aos.instance.number' -Value $value if(-not $Temporary) { Register-PSFConfig -Module 'ax2012.tools' -Name 'active.aos.instance.number' -Scope $configScope } } "InstanceName" { Set-PSFConfig -Module 'ax2012.tools' -Name 'active.aos.instancename' -Value $value $Script:ActiveAosInstancename = $value if(-not $Temporary) { Register-PSFConfig -Module 'ax2012.tools' -Name 'active.aos.instancename' -Scope $configScope } } "DatabaseServer" { Set-PSFConfig -Module 'ax2012.tools' -Name 'active.aos.databaseserver' -Value $value $Script:ActiveAosDatabaseserver = $value if(-not $Temporary) { Register-PSFConfig -Module 'ax2012.tools' -Name 'active.aos.databaseserver' -Scope $configScope } } "DatabaseName" { Set-PSFConfig -Module 'ax2012.tools' -Name 'active.aos.database' -Value $value if(-not $Temporary) { Register-PSFConfig -Module 'ax2012.tools' -Name 'active.aos.database' -Scope $configScope } } "ModelstoreDatabase" { Set-PSFConfig -Module 'ax2012.tools' -Name 'active.aos.modelstoredatabase' -Value $value $Script:ActiveAosModelstoredatabase = $value if(-not $Temporary) { Register-PSFConfig -Module 'ax2012.tools' -Name 'active.aos.modelstoredatabase' -Scope $configScope } } "AosPort" { Set-PSFConfig -Module 'ax2012.tools' -Name 'active.aos.aos.port' -Value $value if(-not $Temporary) { Register-PSFConfig -Module 'ax2012.tools' -Name 'active.aos.aos.port' -Scope $configScope } } "WsdlPort" { Set-PSFConfig -Module 'ax2012.tools' -Name 'active.aos.wsdl.port' -Value $value if(-not $Temporary) { Register-PSFConfig -Module 'ax2012.tools' -Name 'active.aos.wsdl.port' -Scope $configScope } } "NetTcpPort" { Set-PSFConfig -Module 'ax2012.tools' -Name 'active.aos.nettcp.port' -Value $value if(-not $Temporary) { Register-PSFConfig -Module 'ax2012.tools' -Name 'active.aos.nettcp.port' -Scope $configScope } } Default {} } } } <# .SYNOPSIS Start an AX 2012 environment .DESCRIPTION Start AX 2012 services in your environment .PARAMETER Server Name of the computer(s) that you want to work against Default value is the name from the ComputerName from AxActiveAosConfiguration .PARAMETER DisplayName DisplayName of windows service that you want to work against Accepts wildcards for searching. E.g. -DisplayName "*ax*obj*" .PARAMETER Name Name of the Windows Service that you want to work against This parameter is used when piping in the details Designed to work together with the Get-AxEnvironment cmdlet .PARAMETER ShowOutput Switch to instruct the cmdlet to output the status for the service .EXAMPLE PS C:\> Start-AxEnvironment -Server TEST-AOS-01 -DisplayName *ax*obj* This will start the service(s) that match the search pattern "*ax*obj*" on the server named "TEST-AOS-01". .EXAMPLE PS C:\> Start-AxEnvironment -Server TEST-AOS-01 -DisplayName *ax*obj* -ShowOutput This will start the service(s) that match the search pattern "*ax*obj*" on the server named "TEST-AOS-01". It will show the status for the service(s) on the server afterwards. .EXAMPLE PS C:\> Get-AxEnvironment -ComputerName TEST-AOS-01 -Aos | Start-AxEnvironment -ShowOutput This will scan the "TEST-AOS-01" server for all AOS instances and start them. It will show the status for the service(s) on the server afterwards. .NOTES Author: M�tz Jensen (@Splaxi) #> function Start-AxEnvironment { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "")] [CmdletBinding(DefaultParameterSetName = "Default")] param ( [Parameter(ValueFromPipelineByPropertyName = $true, ParameterSetName = "Pipeline")] [Parameter(ParameterSetName = "Default", Position = 1)] [Alias('ComputerName')] [string[]] $Server = $Script:ActiveAosComputername, [Parameter(Mandatory = $true, ParameterSetName = "Default", Position = 2)] [string] $DisplayName, [Parameter(ValueFromPipelineByPropertyName = $true, ParameterSetName = "Pipeline")] [string[]] $Name, [switch] $ShowOutput ) begin { $output = New-Object System.Collections.ArrayList } process { $baseParams = @{ComputerName = $Server; ErrorAction = "SilentlyContinue"} if ($PSCmdlet.ParameterSetName -eq "Pipeline") { $baseParams.Name = $Name } else { if ($DisplayName -notmatch "\*" ) { $DisplayName = "*$DisplayName*" } $baseParams.DisplayName = $DisplayName } Get-Service @baseParams | Start-Service -ErrorAction SilentlyContinue if ($ShowOutput) { $service = Get-Service @baseParams | Select-Object @{Name = "Server"; Expression = {$Server}}, Name, Status, DisplayName $null = $output.Add($service) } } end { if ($ShowOutput) { $output.ToArray() | Select-Object Server, DisplayName, Status, Name } } } <# .SYNOPSIS Stop an AX 2012 environment .DESCRIPTION Stop an AX 2012 services in your environment .PARAMETER Server Name of the computer(s) that you want to work against Default value is the name from the ComputerName from AxActiveAosConfiguration .PARAMETER DisplayName DisplayName of windows service that you want to work against Accepts wildcards for searching. E.g. -DisplayName "*ax*obj*" .PARAMETER Name Name of the Windows Service that you want to work against This parameter is used when piping in the details Designed to work together with the Get-AxEnvironment cmdlet .PARAMETER ShowOutput Switch to instruct the cmdlet to output the status for the service .PARAMETER Force Switch to instruct the cmdlet to force the stopping of the service .EXAMPLE PS C:\> Stop-AxEnvironment -Server TEST-AOS-01 -DisplayName *ax*obj* This will stop the service(s) that match the search pattern "*ax*obj*" on the server named "TEST-AOS-01". .EXAMPLE PS C:\> Stop-AxEnvironment -Server TEST-AOS-01 -DisplayName *ax*obj* -ShowOutput This will stop the service(s) that match the search pattern "*ax*obj*" on the server named "TEST-AOS-01". It will show the status for the service(s) on the server afterwards. .EXAMPLE PS C:\> Get-AxEnvironment -ComputerName TEST-AOS-01 -Aos | Stop-AxEnvironment -ShowOutput This will scan the "TEST-AOS-01" server for all AOS instances and stop them. It will show the status for the service(s) on the server afterwards. .NOTES Author: M�tz Jensen (@Splaxi) #> function Stop-AxEnvironment { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "")] [CmdletBinding(DefaultParameterSetName = "Default")] param ( [Parameter(ValueFromPipelineByPropertyName = $true, ParameterSetName = "Pipeline")] [Parameter(ParameterSetName = "Default", Position = 1)] [Alias('ComputerName')] [string[]] $Server = $Script:ActiveAosComputername, [Parameter(Mandatory = $true, ParameterSetName = "Default", Position = 2)] [string] $DisplayName, [Parameter(ValueFromPipelineByPropertyName = $true, ParameterSetName = "Pipeline")] [string[]] $Name, [switch] $ShowOutput, [switch] $Force ) begin { $output = New-Object System.Collections.ArrayList } process { $baseParams = @{ComputerName = $Server; ErrorAction = "SilentlyContinue"} if ($PSCmdlet.ParameterSetName -eq "Pipeline") { $baseParams.Name = $Name } else { if ($DisplayName -notmatch "\*" ) { $DisplayName = "*$DisplayName*" } $baseParams.DisplayName = $DisplayName } Get-Service @baseParams | Stop-Service -Force:$Force -ErrorAction SilentlyContinue if ($ShowOutput) { $service = Get-Service @baseParams | Select-Object @{Name = "Server"; Expression = {$Server}}, Name, Status, DisplayName $null = $output.Add($service) } } end { if ($ShowOutput) { $output.ToArray() | Select-Object Server, DisplayName, Status, Name } } } |