diff --git a/images/win/Windows2016-Azure.json b/images/win/Windows2016-Azure.json index 6afa6c44d..02976c08a 100644 --- a/images/win/Windows2016-Azure.json +++ b/images/win/Windows2016-Azure.json @@ -80,6 +80,11 @@ "source": "{{ template_dir }}/scripts/ImageHelpers", "destination": "{{user `helper_script_folder`}}" }, + { + "type": "file", + "source": "{{ template_dir }}/scripts/SoftwareReport", + "destination": "{{user `image_folder`}}" + }, { "type": "windows-shell", "inline": [ @@ -984,6 +989,12 @@ "{{ template_dir }}/scripts/Installers/Validate-DiskSpace.ps1" ] }, + { + "type": "powershell", + "inline": [ + "pwsh -File '{{user `image_folder`}}\\SoftwareReport\\SoftwareReport.Generator.ps1'" + ] + }, { "type": "file", "source": "C:\\InstalledSoftware.md", diff --git a/images/win/Windows2019-Azure.json b/images/win/Windows2019-Azure.json index 9cebffb4a..c65982e4e 100644 --- a/images/win/Windows2019-Azure.json +++ b/images/win/Windows2019-Azure.json @@ -80,6 +80,11 @@ "source": "{{ template_dir }}/scripts/ImageHelpers", "destination": "{{user `helper_script_folder`}}" }, + { + "type": "file", + "source": "{{ template_dir }}/scripts/SoftwareReport", + "destination": "{{user `image_folder`}}" + }, { "type": "windows-shell", "inline": [ @@ -975,6 +980,12 @@ "{{ template_dir }}/scripts/Installers/Validate-DiskSpace.ps1" ] }, + { + "type": "powershell", + "inline": [ + "pwsh -File '{{user `image_folder`}}\\SoftwareReport\\SoftwareReport.Generator.ps1'" + ] + }, { "type": "file", "source": "C:\\InstalledSoftware.md", diff --git a/images/win/scripts/SoftwareReport/SoftwareReport.Android.psm1 b/images/win/scripts/SoftwareReport/SoftwareReport.Android.psm1 new file mode 100644 index 000000000..60d7c1854 --- /dev/null +++ b/images/win/scripts/SoftwareReport/SoftwareReport.Android.psm1 @@ -0,0 +1,109 @@ +function Get-AndroidComponentLocation { + param( + [string] $ComponentName + ) + $path = Join-Path $env:ANDROID_HOME $ComponentName + return "Location $path" +} + +function Split-AndroidSDKOutputRow { + param( + [string] $Row + ) + return $Row.Split("|").Trim() +} + +function Create-AndroidTableObject { + param( + [string] $PackageName, + [string] $Description + ) + return [PSCustomObject] @{ + "Package Name" = $PackageName + "Description" = $Description + } +} + +function Get-AndroidSDKManagerPath { + return Join-Path $env:ANDROID_HOME "tools" "bin" "sdkmanager.bat" +} + +function Get-AndroidInstalledPackages { + $androidSDKManagerPath = Get-AndroidSDKManagerPath + $androidSDKManagerList = & $androidSDKManagerPath --list --include_obsolete + $androidInstalledPackages = @() + foreach($packageInfo in $androidSDKManagerList) { + if($packageInfo -Match "Available Packages:") { + break + } + + $androidInstalledPackages += $packageInfo + } + return $androidInstalledPackages +} + +function Build-AndroidSDKToolsTable { + param ( + [Parameter(Mandatory)] + [object] $packageInfo + ) + + return $packageInfo | ForEach-Object { + $packageInfoParts = Split-AndroidSDKOutputRow $_ + $packageName = $packageInfoParts[0] + $packageDescription = $packageInfoParts[2] + ", Revision " + $packageInfoParts[1] + Create-AndroidTableObject -PackageName $packageName -Description $packageDescription + } +} + +function Build-AndroidSDKPlatformTable { + param ( + [Parameter(Mandatory)] + [object] $packageInfo + ) + + return $packageInfo | ForEach-Object { + $packageInfoParts = Split-AndroidSDKOutputRow $_ + $packageName = $packageInfoParts[0].split(";")[1] + $packageDescription = $packageInfoParts[2] + ", Revision " + $packageInfoParts[1] + return Create-AndroidTableObject -PackageName $packageName -Description $packageDescription + } +} + +function Build-AndroidSDKBuildToolsTable { + param ( + [Parameter(Mandatory)] + [object] $packageInfo + ) + + return $packageInfo | ForEach-Object { + $packageInfoParts = Split-AndroidSDKOutputRow $_ + $packageName = $packageInfoParts[0].replace(";", "-") + $packageDescription = "Android SDK Build-Tools, Revision " + $packageInfoParts[1] + return Create-AndroidTableObject -PackageName $packageName -Description $packageDescription + } +} + +function Build-AndroidExtraPackagesTable { + param ( + [Parameter(Mandatory)][AllowEmptyString()] + [string[]] $installedPackages + ) + + $extraPackages = @( + "Android Support Repository", + "Google Play services", + "Google Repository", + "ndk-bundle" + ) + + return $extraPackages | ForEach-Object { + $packageId = $_ + $packageInfo = $installedPackages | Where-Object { $_ -Like "*${packageId}*" } | Select-Object -First 1 + $packageInfoParts = Split-AndroidSDKOutputRow $packageInfo + return [PSCustomObject] @{ + "Package Name" = $packageInfoParts[2] + "Version" = $packageInfoParts[1] + } + } +} \ No newline at end of file diff --git a/images/win/scripts/SoftwareReport/SoftwareReport.Browsers.psm1 b/images/win/scripts/SoftwareReport/SoftwareReport.Browsers.psm1 new file mode 100644 index 000000000..3784b7fa9 --- /dev/null +++ b/images/win/scripts/SoftwareReport/SoftwareReport.Browsers.psm1 @@ -0,0 +1,55 @@ +$browsers = @{ + chrome = @{ + Name="Google Chrome"; + File="chrome.exe" + }; + edge = @{ + Name="Microsoft Edge"; + File="msedge.exe" + }; + firefox = @{ + Name="Mozilla Firefox"; + File="firefox.exe" + } +} + +$webDrivers = @{ + chrome = @{ + Name="Chrome Driver"; + Path="C:\SeleniumWebDrivers\ChromeDriver" + }; + edge = @{ + Name="Microsoft Edge Driver"; + Path="C:\SeleniumWebDrivers\EdgeDriver" + }; + firefox = @{ + Name="Gecko Driver"; + Path="C:\SeleniumWebDrivers\GeckoDriver" + }; + iexplorer = @{ + Name="IE Driver"; + Path="C:\SeleniumWebDrivers\IEDriver" + } +} + +function Get-BrowserVersion { + param( + [string] $Browser + ) + $browserName = $browsers.$Browser.Name + $browserFile = $browsers.$Browser.File + $registryKey = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\$browserFile" + $browserVersion = (Get-Item (Get-ItemProperty $registryKey)."(Default)").VersionInfo.FileVersion + return "$browserName $browserVersion" +} + +function Get-SeleniumWebDriverVersion { + param( + [string] $Driver + ) + $driverName = $webDrivers.$Driver.Name + $driverPath = $webDrivers.$Driver.Path + $versionFileName = "versioninfo.txt"; + $webDriverVersion = Get-Content -Path "$driverPath\$versionFileName" + return "$driverName $webDriverVersion" +} \ No newline at end of file diff --git a/images/win/scripts/SoftwareReport/SoftwareReport.CachedTools.psm1 b/images/win/scripts/SoftwareReport/SoftwareReport.CachedTools.psm1 new file mode 100644 index 000000000..f283d1426 --- /dev/null +++ b/images/win/scripts/SoftwareReport/SoftwareReport.CachedTools.psm1 @@ -0,0 +1,117 @@ +function Get-BoostMarkdown +{ + $Name = "Boost" + $ToolInstances = Get-CachedToolInstances -Name $Name + foreach ($Instance in $ToolInstances) + { + $VersionEnvVar = $Instance.Version.replace(".", "_") + $Instance."Environment Variable" = "BOOST_ROOT_${VersionEnvVar}" + } + + $Content = $ToolInstances | New-MDTable -Columns ([ordered]@{ + Version = "left"; + Architecture = "left"; + "Environment Variable" = "left" + }) + $Content += New-MDHeader "Notes:" -Level 5 + $Content += @' +``` +1. Environment variable "BOOST_ROOT" is not set by default. + Please make sure you set this variable value to proper value + from table above depending on the Boost version you are using. +2. If Boost was built using the boost-cmake project or from Boost 1.70.0 + on it provides a package configuration file for use with find_package's config mode. + This module looks for the package configuration file called BoostConfig.cmake or boost-config.cmake + and stores the result in CACHE entry "Boost_DIR". If found, the package configuration file + is loaded and this module returns with no further action. + See documentation of the Boost CMake package configuration for details on what it provides. + Set Boost_NO_BOOST_CMAKE to ON, to disable the search for boost-cmake. + Link: https://cmake.org/cmake/help/latest/module/FindBoost.html +``` +'@ + + return Build-MarkdownElement -Head $Name -Content $Content +} + +function Get-GoMarkdown +{ + $Name = "Go" + $ToolInstances = Get-CachedToolInstances -Name $Name -VersionCommand "version" + foreach ($Instance in $ToolInstances) + { + $Version = [System.Version]($Instance.Version -Split(" "))[0] + $Instance."Environment Variable" = "GOROOT_$($Version.major)_$($Version.minor)_X64" + } + + $Content = $ToolInstances | New-MDTable -Columns ([ordered]@{ + Version = "left"; + Architecture = "left"; + "Environment Variable" = "left" + }) + + return Build-MarkdownElement -Head $Name -Content $Content +} + +function Get-NodeMarkdown +{ + $Name = "Node" + $ToolInstances = Get-CachedToolInstances -Name $Name + $Content = $ToolInstances | New-MDTable -Columns ([ordered]@{Version = "left"; Architecture = "left"}) + + return Build-MarkdownElement -Head $Name -Content $Content +} + +function Get-PythonMarkdown +{ + $Name = "Python" + $ToolInstances = Get-CachedToolInstances -Name $Name -VersionCommand "--version" + $Content = $ToolInstances | New-MDTable -Columns ([ordered]@{Version = "left"; Architecture = "left"}) + + return Build-MarkdownElement -Head $Name -Content $Content +} + +function Get-RubyMarkdown +{ + $Name = "Ruby" + $ToolInstances = Get-CachedToolInstances -Name $Name -VersionCommand "--version" + $Content = $ToolInstances | New-MDTable -Columns ([ordered]@{Version = "left"; Architecture = "left"}) + + return Build-MarkdownElement -Head $Name -Content $Content +} + +function Get-PyPyMarkdown +{ + $Name = "PyPy" + $ToolInstances = Get-CachedToolInstances -Name $Name + foreach ($Instance in $ToolInstances) + { + $Instance."PyPy Version" = @() + $Instance."Python Version" = $Instance.Version + foreach ($Arch in $Instance.Architecture_Array) + { + $pythonExePath = Join-Path $Instance.Path $Arch | Join-Path -ChildPath "python.exe" + $Instance."PyPy Version" += (& $pythonExePath -c "import sys;print(sys.version.split('\n')[1])").Trim("[]") + } + } + + $Content = $ToolInstances | New-MDTable -Columns ([ordered]@{ + "Python Version" = "left"; + Architecture = "left"; + "PyPy Version" = "left" + }) + + return Build-MarkdownElement -Head $Name -Content $Content +} + +function Build-CachedToolsMarkdown +{ + $markdown = "" + $markdown += Get-BoostMarkdown + $markdown += Get-GoMarkdown + $markdown += Get-NodeMarkdown + $markdown += Get-PythonMarkdown + $markdown += Get-RubyMarkdown + $markdown += Get-PyPyMarkdown + + return $markdown +} \ No newline at end of file diff --git a/images/win/scripts/SoftwareReport/SoftwareReport.Common.psm1 b/images/win/scripts/SoftwareReport/SoftwareReport.Common.psm1 new file mode 100644 index 000000000..95b73a2f5 --- /dev/null +++ b/images/win/scripts/SoftwareReport/SoftwareReport.Common.psm1 @@ -0,0 +1,233 @@ +function Get-OSName { + return (Get-CimInstance -ClassName Win32_OperatingSystem).Caption +} + +function Get-OSVersion { + $systemInfo = Get-CimInstance -ClassName Win32_OperatingSystem + $OSVersion = $systemInfo.Version + $OSBuild = $systemInfo.BuildNumber + return "OS Version: $OSVersion Build $OSBuild" +} + +function Get-JavaVersionsList { + param( + [string] $DefaultVersion + ) + + $postfix = "" + $javaDir = Join-Path $env:PROGRAMFILES "Java" + return Get-ChildItem $javaDir | ForEach-Object { + $javaBinPath = Join-Path $_ "bin" + $rawVersion = & cmd /c "`"$javaBinPath\java.exe`" -version 2>&1" | Out-String + $rawVersion -match 'openjdk version "(?.+)"' | Out-Null + $version = $Matches.Version + if ($version -match $DefaultVersion) { + $postfix = "(default)" + } else { + $postfix = "" + } + return "Java $version $postfix" + } | Sort-Object { + $version = ($_.Split(" ")[1]).Split("_")[0] + return [System.Version]$version + } +} + +function Get-RustVersion { + $rustVersion = [regex]::matches($(rustc --version), "\d+\.\d+\.\d+").Value + return "Rust ${rustVersion}" +} + +function Get-PythonVersion { + return & python --version +} + +function Get-PowershellCoreVersion { + return & pwsh --version +} + +function Get-RubyVersion { + $rubyVersion = $(ruby --version).split(" ")[1] + return "Ruby $rubyVersion" +} + +function Get-GoVersion { + $(go version) -match "go(?\d+\.\d+\.\d+)" | Out-Null + $goVersion = $Matches.Version + return "Go $goVersion" +} + +function Get-PHPVersion { + ($(php --version) | Out-String) -match "PHP (?\d+\.\d+\.\d+)" | Out-Null + $phpVersion = $Matches.Version + return "PHP $phpVersion" +} + +function Get-JuliaVersion { + $juliaVersion = [regex]::matches($(julia --version), "\d+\.\d+\.\d+").Value + return "Julia $juliaVersion" +} + +function Get-PerlVersion { + ($(perl --version) | Out-String) -match "\(v(?\d+\.\d+\.\d+)\)" | Out-Null + $perlVersion = $Matches.Version + return "Perl $perlVersion" +} + +function Get-NodeVersion { + $nodeVersion = $(node --version).split("v")[1] + return "Node $nodeVersion" +} + +function Get-ChocoVersion { + ($(choco version) | Out-String) -match "v(?\d+\.\d+\.\d+)" | Out-Null + $chocoVersion = $Matches.Version + return "Chocolatey $chocoVersion" +} + +function Get-VcpkgVersion { + ($(vcpkg version) | Out-String) -match "version (?\d+\.\d+\.\d+)" | Out-Null + $vcpkgVersion = $Matches.Version + return "Vcpkg $vcpkgVersion" +} + +function Get-NPMVersion { + return "NPM $(npm -version)" +} + +function Get-YarnVersion { + return "Yarn $(yarn -version)" +} + +function Get-RubyGemsVersion { + return "RubyGems $(gem --version)" +} + +function Get-HelmVersion { + ($(helm version --short) | Out-String) -match "v(?\d+\.\d+\.\d+)" | Out-Null + $helmVersion = $Matches.Version + return "Helm $helmVersion" +} + +function Get-PipVersion { + ($(pip --version) | Out-String) -match "(?pip [\d\.]+) .+ (?\(python [\d\.]+\))" | Out-Null + $pipVersion = $Matches.Version + $pythonVersion = $Matches.Python + return "$pipVersion $pythonVersion" +} + +function Get-CondaVersion { + $condaVersion = & "$env:CONDA\Scripts\conda.exe" --version + return "Mini$condaVersion" +} + +function Get-ComposerVersion { + ($(composer --version)) -match "Composer version (?\d+\.\d+\.\d+)" | Out-Null + $composerVersion = $Matches.Version + return "Composer $composerVersion" +} + +function Get-AntVersion { + ($(ant -version) | Out-String) -match "version (?\d+\.\d+\.\d+)" | Out-Null + $antVersion = $Matches.Version + return "Ant $antVersion" +} + +function Get-MavenVersion { + ($(mvn -version) | Out-String) -match "Apache Maven (?\d+\.\d+\.\d+)" | Out-Null + $mavenVersion = $Matches.Version + return "Maven $mavenVersion" +} + +function Get-GradleVersion { + ($(gradle -version) | Out-String) -match "Gradle (?\d+\.\d+)" | Out-Null + $gradleVersion = $Matches.Version + return "Gradle $gradleVersion" +} + +function Get-DotnetSdks { + $sdksRawList = dotnet --list-sdks + $sdkVersions = ($sdksRawList | Foreach-Object {$_.Split()[0]}) -join ' ' + $sdkPath = $sdksRawList[0].Split(' ', 2)[1] -replace '\[|]' + [PSCustomObject]@{ + Versions = $sdkVersions + Path = $sdkPath + } +} + +function Get-DotnetRuntimes { + $runtimesRawList = dotnet --list-runtimes + $runtimesRawList | Group-Object {$_.Split()[0]} | ForEach-Object { + $runtimeName = $_.Name + $runtimeVersions = ($_.Group | Foreach-Object {$_.split()[1]}) -join ' ' + $runtimePath = $_.Group[0].Split(' ', 3)[2] -replace '\[|]' + [PSCustomObject]@{ + "Runtime" = $runtimeName + "Versions" = $runtimeVersions + "Path" = $runtimePath + } + } +} + +function Get-DotnetFrameworkTools { + $path = "${env:ProgramFiles(x86)}\Microsoft SDKs\Windows\*\*\NETFX*" + $frameworkVersions = @() + Get-ChildItem -Path $path -Directory | ForEach-Object { + $frameworkVersions += ($_.Name -Split(" "))[1] + $frameworkPath = $_.Fullname -Replace " \d+\.\d+(\.\d+)?", " " + } + [PSCustomObject]@{ + Versions = $frameworkVersions -Join " " + Path = $frameworkPath + } +} + +function Get-PowerShellAzureModules { + # Module names + $names = @{ + 'az' = 'Az' + 'azurerm' = 'AzureRM' + 'azure' = 'Azure' + } + + # Get default module version + $defaults = @{ + 'azurerm' = (Get-Module -Name AzureRM -ListAvailable).Version + 'azure' = (Get-Module -Name Azure -ListAvailable).Version + } + + $modulesPath = "C:\Modules" + $modules = Get-ChildItem -Path $modulesPath | Sort-Object Name | Group-Object {$_.Name.Split('_')[0]} + $modules | ForEach-Object { + $group = $_.group | Sort-Object {[Version]$_.Name.Split('_')[1]} + $moduleName = $names[$_.Name] + $moduleVersions = $group | ForEach-Object {$_.Name.Split('_')[1]} + $moduleVersions = $moduleVersions -join '
' + $modulePath = (($group.FullName).Split("_"))[0] + '_\' + + # set default version + $defaultVersion = $defaults[$_.Name] + if ($defaultVersion) { + $moduleVersions = $moduleVersions.Replace($defaultVersion, "$defaultVersion [Installed]") + } + + [PSCustomObject]@{ + Module = $moduleName + Version = $moduleVersions + Path = $modulePath + } + } +} + +function Get-CachedDockerImages { + return (docker images --digests --format "* {{.Repository}}:{{.Tag}}").Split("*") | Where-Object { $_ } +} + +function Get-PacmanVersion { + $msys2BinDir = "C:\msys64\usr\bin" + $pacmanPath = Join-Path $msys2BinDir "pacman.exe" + $rawVersion = & $pacmanPath --version + $rawVersion.Split([System.Environment]::NewLine)[1] -match "\d+\.\d+(\.\d+)?" | Out-Null + $pacmanVersion = $matches[0] + return "- Pacman $pacmanVersion" +} diff --git a/images/win/scripts/SoftwareReport/SoftwareReport.Generator.ps1 b/images/win/scripts/SoftwareReport/SoftwareReport.Generator.ps1 new file mode 100644 index 000000000..a7617a4c4 --- /dev/null +++ b/images/win/scripts/SoftwareReport/SoftwareReport.Generator.ps1 @@ -0,0 +1,201 @@ +# Install MarkdownPS module for software report generation +Install-Module MarkdownPS -Force -Scope AllUsers + +Import-Module MarkdownPS +Import-Module (Join-Path $PSScriptRoot "SoftwareReport.Helpers.psm1") -DisableNameChecking +Import-Module (Join-Path $PSScriptRoot "SoftwareReport.Common.psm1") -DisableNameChecking +Import-Module (Join-Path $PSScriptRoot "SoftwareReport.Tools.psm1") -DisableNameChecking +Import-Module (Join-Path $PSScriptRoot "SoftwareReport.Browsers.psm1") -DisableNameChecking +Import-Module (Join-Path $PSScriptRoot "SoftwareReport.CachedTools.psm1") -DisableNameChecking +Import-Module (Join-Path $PSScriptRoot "SoftwareReport.VisualStudio.psm1") -DisableNameChecking +Import-Module (Join-Path $PSScriptRoot "SoftwareReport.Android.psm1") -DisableNameChecking + +$markdown = "" + +$OSName = Get-OSName +$markdown += New-MDHeader "$OSName" -Level 1 + +$OSVersion = Get-OSVersion +$markdown += New-MDList -Style Unordered -Lines @( + "$OSVersion" + "Image Version: $env:ImageVersion" +) + +$markdown += New-MDHeader "Installed Software" -Level 2 +$markdown += New-MDHeader "Language and Runtime" -Level 3 + +$markdown += New-MDList -Lines (Get-JavaVersionsList -DefaultVersion "1.8.0") -Style Unordered -NoNewLine +$markdown += New-MDList -Style Unordered -Lines @( + (Get-RustVersion), + (Get-PythonVersion), + (Get-RubyVersion), + (Get-GoVersion), + (Get-PHPVersion), + (Get-JuliaVersion), + (Get-PerlVersion), + (Get-PowershellCoreVersion), + (Get-NodeVersion) +) + +$markdown += New-MDHeader "Package Management" -Level 3 +$markdown += New-MDList -Style Unordered -Lines @( + (Get-ChocoVersion), + (Get-VcpkgVersion), + (Get-NPMVersion), + (Get-YarnVersion), + (Get-PipVersion), + (Get-CondaVersion) + (Get-RubyGemsVersion), + (Get-HelmVersion), + (Get-ComposerVersion) +) + +$markdown += New-MDHeader "Project Management" -Level 3 +$markdown += New-MDList -Style Unordered -Lines @( + (Get-AntVersion), + (Get-MavenVersion), + (Get-GradleVersion) +) + +$markdown += New-MDHeader "Tools" -Level 3 +$markdown += New-MDList -Style Unordered -Lines @( + (Get-AzCosmosDBEmulatorVersion), + (Get-BazelVersion), + (Get-BazeliskVersion), + (Get-CMakeVersion), + (Get-DockerVersion), + (Get-DockerComposeVersion), + (Get-GitVersion), + (Get-GitLFSVersion), + (Get-InnoSetupVersion), + (Get-JQVersion), + (Get-KubectlVersion), + (Get-KindVersion), + (Get-MinGWVersion), + (Get-MySQLVersion), + (Get-MercurialVersion), + (Get-NSISVersion), + (Get-OpenSSLVersion), + (Get-PackerVersion), + (Get-SQLPSVersion), + (Get-SQLServerPSVersion), + (Get-SVNVersion), + (Get-GHCVersion), + (Get-CabalVersion), + (Get-StackVersion), + (Get-WinAppDriver), + (Get-ZstdVersion), + (Get-VSWhereVersion), + (Get-7zipVersion) +) + +$markdown += New-MDHeader "CLI Tools" -Level 3 +$markdown += New-MDList -Style Unordered -Lines @( + (Get-AzureCLIVersion), + (Get-AzureDevopsExtVersion), + (Get-AWSCLIVersion), + (Get-AWSSAMVersion), + (Get-AlibabaCLIVersion), + (Get-CloudFoundryVersion), + (Get-HubVersion) +) + +$markdown += New-MDHeader "Browsers and webdrivers" -Level 3 +$markdown += New-MDList -Style Unordered -Lines @( + (Get-BrowserVersion -Browser "chrome"), + (Get-SeleniumWebDriverVersion -Driver "chrome"), + (Get-BrowserVersion -Browser "edge"), + (Get-SeleniumWebDriverVersion -Driver "edge"), + (Get-BrowserVersion -Browser "firefox"), + (Get-SeleniumWebDriverVersion -Driver "firefox"), + (Get-SeleniumWebDriverVersion -Driver "iexplorer") +) + +$markdown += New-MDHeader "MSYS2" -Level 3 +$markdown += Get-PacmanVersion +$markdown += New-MDNewLine +$markdown += @' +``` +Location: C:\msys64 + +Note: MSYS2 is pre-installed on image but not added to PATH. +``` +'@ +$markdown += New-MDNewLine + +$markdown += New-MDHeader "Cached Tools" -Level 3 +$markdown += (Build-CachedToolsMarkdown) +$markdown += New-MDNewLine + +$vs = Get-VisualStudioVersion +$markdown += New-MDHeader "$($vs.Name)" -Level 3 +$markdown += $vs | New-MDTable +$markdown += New-MDNewLine + +$markdown += New-MDHeader "Workloads, components and extensions:" -Level 4 +$markdown += New-MDNewLine +$markdown += ((Get-VisualStudioComponents) + (Get-VisualStudioExtenions)) | New-MDTable +$markdown += New-MDNewLine + +$markdown += New-MDHeader ".NET Core SDK" -Level 3 +$sdk = Get-DotnetSdks +$markdown += "``Location $($sdk.Path)``" +$markdown += New-MDNewLine +$markdown += New-MDList -Lines $sdk.Versions -Style Unordered + +$markdown += New-MDHeader ".NET Core Runtime" -Level 3 +Get-DotnetRuntimes | Foreach-Object { + $path = $_.Path + $versions = $_.Versions + $markdown += "``Location $path``" + $markdown += New-MDNewLine + $markdown += New-MDList -Lines $versions -Style Unordered +} + +$markdown += New-MDHeader ".NET Framework" -Level 3 +$frameworks = Get-DotnetFrameworkTools +$markdown += "``Location $($frameworks.Path)``" +$markdown += New-MDNewLine +$markdown += New-MDList -Lines $frameworks.Versions -Style Unordered + +$markdown += New-MDHeader "Azure Powershell Modules" -Level 3 +$markdown += Get-PowerShellAzureModules | New-MDTable +$markdown += @' +``` +Azure PowerShell module 2.1.0 and AzureRM PowerShell module 2.1.0 are installed +and are available via 'Get-Module -ListAvailable'. +All other versions are saved but not installed. +``` +'@ +$markdown += New-MDNewLine + +# Android section +$androidInstalledPackages = Get-AndroidInstalledPackages + +$markdown += New-MDHeader "Android SDK Tools" -Level 3 +$androidSDKTools = $androidInstalledPackages | Where-Object { $_ -Match "Android SDK Tools" -or $_ -Match "Android SDK Platform-Tools" } +$markdown += Build-AndroidSDKToolsTable $androidSDKTools | New-MDTable +$markdown += New-MDNewLine + +$markdown += New-MDHeader "Android SDK Platforms" -Level 3 +$androidSDKPlatforms = $androidInstalledPackages | Where-Object { $_ -Match "Android SDK Platform " } +$markdown += New-MDInlineCode -Text (Get-AndroidComponentLocation -ComponentName "platforms") +$markdown += New-MDNewLine +$markdown += Build-AndroidSDKPlatformTable $androidSDKPlatforms | New-MDTable +$markdown += New-MDNewLine + +$markdown += New-MDHeader "Android SDK Build-Tools" -Level 3 +$androidSDKBuildTools = $androidInstalledPackages | Where-Object { $_ -Match "Android SDK Build-Tools" } +$markdown += New-MDInlineCode -Text (Get-AndroidComponentLocation -ComponentName "build-tools") +$markdown += New-MDNewLine +$markdown += Build-AndroidSDKBuildtoolsTable $androidSDKBuildTools | New-MDTable +$markdown += New-MDNewLine + +$markdown += New-MDHeader "Android Extra Packages" -Level 3 +$markdown += Build-AndroidExtraPackagesTable $androidInstalledPackages | New-MDTable +$markdown += New-MDNewLine + +$markdown += New-MDHeader "Cached Docker images" -Level 3 +$markdown += New-MDList -Style Unordered -Lines @(Get-CachedDockerImages) + +$markdown | Out-File -FilePath "C:\InstalledSoftware.md" \ No newline at end of file diff --git a/images/win/scripts/SoftwareReport/SoftwareReport.Helpers.psm1 b/images/win/scripts/SoftwareReport/SoftwareReport.Helpers.psm1 new file mode 100644 index 000000000..11c0f5c5c --- /dev/null +++ b/images/win/scripts/SoftwareReport/SoftwareReport.Helpers.psm1 @@ -0,0 +1,105 @@ +function Build-MarkdownElement +{ + <# + .SYNOPSIS + Build markdown element for cached tool. + + .DESCRIPTION + Build markdown element that contains name of tool, set of versions and additional notes. + + .PARAMETER Head + Header of cached tool markdown element + + .PARAMETER Content + Array of lines that contains required information about installed tool instances. + #> + + param + ( + [String] $Head, + [Object[]] $Content + ) + + $markdown = New-MDHeader $Head -Level 4 + $markdown += New-MDParagraph -Lines $Content + + return $markdown +} + +function Get-CachedToolInstances +{ + <# + .SYNOPSIS + Returns hastable of installed cached tools. + + .DESCRIPTION + Return hastable that contains versions and architectures for selected cached tool. + + .PARAMETER Name + Name of cached tool. + + .PARAMETER VersionCommand + Optional parameter. Command to return version of system default tool. + + .EXAMPLE + Get-CachedToolInstances -Name "Python" -VersionCommand "--version" + + #> + + param + ( + [String] $Name, + [String] $VersionCommand + ) + + $toolInstances = @() + $toolPath = Join-Path -Path $env:AGENT_TOOLSDIRECTORY -ChildPath $Name + + # Get all installed versions from TOOLSDIRECTORY folder + $versions = Get-ChildItem $toolPath | Sort-Object { [System.Version]$_.Name } + foreach ($version in $versions) + { + $instanceInfo = @{} + + # Create instance hashtable + [string]$instanceInfo.Path = Join-Path -Path $toolPath -ChildPath $version.Name + [string]$instanceInfo.Version = $version.Name + + ### Temporary workaround. Currently Boost instances don't have architecture subfolders. + if ($Name -eq "Boost") + { + [string]$instanceInfo.Architecture = "x64, x86" + $toolInstances += $instanceInfo + continue + } + + # Get all architectures for current version + [array]$instanceInfo.Architecture_Array = Get-ChildItem $version.FullName -Name -Directory | Where-Object { $_ -match "^x[0-9]{2}$" } + [string]$instanceInfo.Architecture = $instanceInfo.Architecture_Array -Join ", " + + # Add (default) postfix to version name, in case if current version is in environment path + if (-not ([string]::IsNullOrEmpty($VersionCommand))) + { + $defaultVersion = $(& ($Name.ToLower()) $VersionCommand 2>&1) + $defaultToolVersion = $defaultVersion | Select-String -Pattern "\d+\.\d+\.\d+" -AllMatches ` + | ForEach-Object { $_.Matches.Value } + + if ([version]$version.Name -eq [version]$defaultToolVersion) + { + $instanceInfo.Version += " (Default)" + } + } + + $toolInstances += $instanceInfo + } + + return $toolInstances +} + +function New-MDNewLine { + param ( + [int] $Count = 1 + ) + $newLineSymbol = [System.Environment]::NewLine + return $newLineSymbol * $Count +} \ No newline at end of file diff --git a/images/win/scripts/SoftwareReport/SoftwareReport.Tools.psm1 b/images/win/scripts/SoftwareReport/SoftwareReport.Tools.psm1 new file mode 100644 index 000000000..510269c25 --- /dev/null +++ b/images/win/scripts/SoftwareReport/SoftwareReport.Tools.psm1 @@ -0,0 +1,201 @@ +function Get-AzCosmosDBEmulatorVersion { + $regKey = gci HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\* | gp | ? { $_.DisplayName -eq 'Azure Cosmos DB Emulator' } + $installDir = $regKey.InstallLocation + $exeFilePath = Join-Path $installDir 'CosmosDB.Emulator.exe' + $version = (Get-Item $exeFilePath).VersionInfo.FileVersion + return "Azure CosmosDb Emulator $version" +} + +function Get-BazelVersion { + ((cmd /c "bazel --version 2>&1") | Out-String) -match "bazel (?\d+\.\d+\.\d+)" | Out-Null + $bazelVersion = $Matches.Version + return "Bazel $bazelVersion" +} + +function Get-BazeliskVersion { + ((cmd /c "bazelisk version 2>&1") | Out-String) -match "Bazelisk version: v(?\d+\.\d+\.\d+)" | Out-Null + $bazeliskVersion = $Matches.Version + return "Bazelisk $bazeliskVersion" +} + +function Get-CMakeVersion { + ($(cmake -version) | Out-String) -match "cmake version (?\d+\.\d+\.\d+)" | Out-Null + $cmakeVersion = $Matches.Version + return "CMake $cmakeVersion" +} + +function Get-DockerVersion { + $dockerVersion = $(docker version --format "{{.Server.Version}}") + return "Docker $dockerVersion" +} + +function Get-DockerComposeVersion { + $(docker-compose --version) -match "docker-compose version (?\d+\.\d+\.\d+)" | Out-Null + $dockerComposeVersion = $Matches.Version + return "Docker-compose $dockerComposeVersion" +} + +function Get-GitVersion { + $(git version) -match "git version (?\d+\.\d+\.\d+)" | Out-Null + $gitVersion = $Matches.Version + return "Git $gitVersion" +} + +function Get-GitLFSVersion { + $(git-lfs version) -match "git-lfs\/(?\d+\.\d+\.\d+)" | Out-Null + $gitLfsVersion = $Matches.Version + return "Git LFS $gitLfsVersion" +} + +function Get-InnoSetupVersion { + return $(choco list --local-only innosetup) | Select-String -Pattern "InnoSetup" +} + +function Get-JQVersion { + $jqVersion = ($(jq --version) -Split "jq-")[1] + return "jq $jqVersion" +} + +function Get-KubectlVersion { + $(kubectl version --client=true --short=true) -match "Client Version: v(?.+)" | Out-Null + $kubectlVersion = $Matches.Version + return "Kubectl $kubectlVersion" +} + +function Get-KindVersion { + $(kind version) -match "kind v(?\d+\.\d+\.\d+)" | Out-Null + $kindVersion = $Matches.Version + return "Kind $kindVersion" +} + +function Get-MinGWVersion { + (gcc --version | Select-String -Pattern "MinGW-W64 project") -match "(?\d+\.\d+\.\d+)" | Out-Null + $mingwVersion = $Matches.Version + return "Mingw-w64 $mingwVersion" +} + +function Get-MySQLVersion { + $mysqlCommand = Get-Command -Name "mysql" + $mysqlVersion = $mysqlCommand.Version.ToString() + return "MySQL $mysqlVersion" +} + +function Get-MercurialVersion { + ($(hg --version) | Out-String) -match "version (?\d+\.\d+\.?\d*)" | Out-Null + $mercurialVersion = $Matches.Version + return "Mercurial $mercurialVersion" +} + +function Get-NSISVersion { + $(choco list --local-only nsis | Out-String) -match "nsis (?\d+\.\d+\.?\d*\.?\d*)" | Out-Null + $nsisVersion = $Matches.Version + return "NSIS $nsisVersion" +} + +function Get-OpenSSLVersion { + $(openssl version) -match "OpenSSL (?\d+\.\d+\.\d+\w?) " | Out-Null + $opensslVersion = $Matches.Version + return "OpenSSL $opensslVersion" +} + +function Get-PackerVersion { + return "Packer $(packer --version)" +} + +function Get-SQLPSVersion { + $module = Get-Module -Name SQLPS -ListAvailable + $version = $module.Version + return "SQLPS $version" +} + +function Get-SQLServerPSVersion { + $module = Get-Module -Name SQLServer -ListAvailable + $version = $module.Version + return "SQLServer PS $version" +} + +function Get-SVNVersion { + $svnVersion = $(svn --version --quiet) + return "Subversion (SVN) $svnVersion" +} + +function Get-VSWhereVersion { + ($(Get-Command -Name vswhere).FileVersionInfo.ProductVersion) -match "(?\d+\.\d+\.\d+)" | Out-Null + $vswhereVersion = $Matches.Version + return "VSWhere $vswhereVersion" +} + +function Get-WinAppDriver { + $winAppDriverVersion = [System.Diagnostics.FileVersionInfo]::GetVersionInfo("C:\Program Files (x86)\Windows Application Driver\WinAppDriver.exe").FileVersion + return "WinAppDriver $winAppDriverVersion" +} + +function Get-ZstdVersion { + $(zstd --version) -match "v(?\d+\.\d+\.\d+)" | Out-Null + $zstdVersion = $Matches.Version + return "zstd $zstdVersion" +} + +function Get-AzureCLIVersion { + $azureCLIVersion = $(az version) | ConvertFrom-Json | Foreach{ $_."azure-cli" } + return "Azure CLI $azureCLIVersion" +} + +function Get-AzureDevopsExtVersion { + $azureDevExtVersion = (az version | ConvertFrom-Json | Foreach{ $_."extensions" })."azure-devops" + return "Azure DevOps CLI extension $azureDevExtVersion" +} + +function Get-AWSCLIVersion { + $(aws --version) -match "aws-cli\/(?\d+\.\d+\.\d+)" | Out-Null + $awscliVersion = $Matches.Version + return "AWS CLI $awscliVersion" +} + +function Get-AWSSAMVersion { + $(sam --version) -match "version (?\d+\.\d+\.\d+)" | Out-Null + $awssamVersion = $Matches.Version + return "AWS SAM CLI $awssamVersion" +} + +function Get-AlibabaCLIVersion { + $(aliyun --version | Select-String "Alibaba Cloud Command Line Interface") -match "(?\d+\.\d+\.\d+)" | Out-Null + $alicliVersion = $Matches.Version + return "Alibaba CLI $alicliVersion" +} + +function Get-CloudFoundryVersion { + $(cf version) -match "(?\d+\.\d+\.\d+)" | Out-Null + $cfVersion = $Matches.Version + return "Cloud Foundry CLI $cfVersion" +} + +function Get-HubVersion { + ($(hub version) | Select-String -Pattern "hub version") -match "hub version (?\d+\.\d+\.\d+)" | Out-Null + $hubVersion = $Matches.Version + return "Hub CLI $hubVersion" +} + +function Get-7zipVersion { + (7z | Out-String) -match "7-Zip (?\d+\.\d+\.?\d*)" | Out-Null + $version = $Matches.Version + return "7zip $version" +} + +function Get-GHCVersion { + ((ghc --version) | Out-String) -match "version (?\d+\.\d+\.\d+)" | Out-Null + $ghcVersion = $Matches.Version + return "ghc $ghcVersion" +} + +function Get-CabalVersion { + ((cabal --version) | Out-String) -match "version (?\d+\.\d+\.\d+\.\d+)" | Out-Null + $cabalVersion = $Matches.Version + return "Cabal $cabalVersion" +} + +function Get-StackVersion { + ((stack --version --quiet) | Out-String) -match "Version (?\d+\.\d+\.\d+)," | Out-Null + $stackVersion = $Matches.Version + return "Stack $stackVersion" +} \ No newline at end of file diff --git a/images/win/scripts/SoftwareReport/SoftwareReport.VisualStudio.psm1 b/images/win/scripts/SoftwareReport/SoftwareReport.VisualStudio.psm1 new file mode 100644 index 000000000..562902476 --- /dev/null +++ b/images/win/scripts/SoftwareReport/SoftwareReport.VisualStudio.psm1 @@ -0,0 +1,65 @@ +function Get-VisualStudioPackages +{ + $packagePath = "$env:ProgramData\Microsoft\VisualStudio\Packages\_Instances\*\state.packages.json" + $instanceFolders = Get-ChildItem -Path $packagePath + (Get-Content -Path $instanceFolders | ConvertFrom-Json).packages +} + +function Get-VisualStudioVersion { + $vsVersion = vswhere -format json | ConvertFrom-Json + [PSCustomObject]@{ + Name = $vsVersion.displayName + Version = $vsVersion.installationVersion + Path = $vsVersion.installationPath + } +} + +function Get-VisualStudioComponents { + $vsPackages = Get-VisualStudioPackages | Where-Object type -in 'Component', 'Workload' + $vsPackages | Sort-Object Id, Version | Select-Object @{n = 'Package'; e = {$_.Id}}, Version | + Where-Object { $_.Package -notmatch "[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}" } +} + +function Get-WixVersion { + $regKey = "HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*" + $installedApplications = Get-ItemProperty -Path $regKey + ($installedApplications | Where-Object { $_.DisplayName -match "wix" } | Select-Object -First 1).DisplayVersion +} + +function Get-WDKVersion { + $regKey = "HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*" + $installedApplications = Get-ItemProperty -Path $regKey + ($installedApplications | Where-Object { $_.DisplayName -eq 'Windows Driver Kit' } | Select-Object -First 1).DisplayVersion +} + +function Get-VisualStudioExtenions { + # Wix + $vs = (Get-VisualStudioVersion).Name.Split()[-1] + $wixPackageVersion = (Get-VisualStudioPackages | Where-Object {$_.id -match 'WixToolset.VisualStudioExtension.Dev' -and $_.type -eq 'vsix'}).Version + $wixExtensionVersion = Get-WixVersion + + # WDK + $wdkPackageVersion = Get-VSExtensionVersion -packageName 'Microsoft.Windows.DriverKit' + $wdkExtensionVersion = Get-WDKVersion + + # SSDT + $analysisPackageVersion = Get-VSExtensionVersion -packageName '04a86fc2-dbd5-4222-848e-911638e487fe' + $reportingPackageVersion = Get-VSExtensionVersion -packageName '717ad572-c4b7-435c-c166-c2969777f718' + + $integrationPackageName = ($vs -match "2019") ? '851E7A09-7B2B-4F06-A15D-BABFCB26B970' : 'D1B09713-C12E-43CC-9EF4-6562298285AB' + $integrationPackageVersion = Get-VSExtensionVersion -packageName $integrationPackageName + + $extensions = @( + @{Package = 'SSDT Microsoft Analysis Services Projects'; Version = $analysisPackageVersion} + @{Package = 'SSDT SQL Server Integration Services Projects'; Version = $integrationPackageVersion} + @{Package = 'SSDT Microsoft Reporting Services Projects'; Version = $reportingPackageVersion} + @{Package = 'Windows Driver Kit'; Version = $wixPackageVersion} + @{Package = 'Windows Driver Kit Visual Studio Extension'; Version = $wdkExtensionVersion} + @{Package = 'WIX Toolset'; Version = $wixPackageVersion} + @{Package = "WIX Toolset Studio $vs Extension"; Version = $wixExtensionVersion} + ) + + $extensions | Foreach-Object { + [PSCustomObject]$_ + } | Select-Object Package, Version +} \ No newline at end of file