diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7637a54 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/Packages +/Logs diff --git a/AZURE_APP_CONFIGURATION.md b/AZURE_APP_CONFIGURATION.md new file mode 100644 index 0000000..262f0f4 --- /dev/null +++ b/AZURE_APP_CONFIGURATION.md @@ -0,0 +1,103 @@ +# Azure AD Application Configuration for WinGet-Wrapper + +## Background + +The WinGet-Wrapper tool uses Microsoft Graph API to interact with Intune. By default, it uses a built-in application ID, but due to recent Microsoft infrastructure changes and security policies, it's recommended to create your own Azure AD application registration. This ensures: + +1. Better security control over the application +2. Avoidance of potential throttling issues +3. Clear audit trails in your Azure environment +4. Prevention of authentication issues related to Microsoft's first-party app verification changes + +## Creating Your Azure AD Application + +### Step 1: Create the Application Registration +1. Log in to the Azure Portal (portal.azure.com) +2. Navigate to Azure Active Directory → App registrations +3. Click "New registration" +4. Configure the following: + - Name: "WinGet-Wrapper-App" (or your preferred name) + - Supported account types: "Accounts in this organizational directory only" + - Click "Register" +5. After creation, note down the "Application (client) ID" - you'll need this later + +### Step 2: Configure Authentication +1. In your app registration, go to "Authentication" in the left menu +2. Click "Add a platform" +3. Select "Mobile and desktop applications" +4. Check the box for "https://login.microsoftonline.com/common/oauth2/nativeclient" +5. Click "Configure" + +This configuration is crucial because the PowerShell scripts use interactive authentication, which requires a proper redirect URI. + +### Step 3: Configure API Permissions +1. Go to "API permissions" in the left menu +2. Click "Add a permission" +3. Select "Microsoft Graph" +4. Choose "Application permissions" +5. Search for and select "DeviceManagementApps.ReadWrite.All" +6. Click "Add permissions" +7. Click "Grant admin consent" and confirm + +## Updating the Scripts + +You need to update the ClientID in the following files: + +### Option 1: Modify the Script Directly +Update `WinGet-WrapperImportFromCSV.ps1`: +```powershell +#ClientID to connect to MSGraph/InTune with Connect-MSIntuneGraph +[Parameter(Mandatory = $False)] +[string]$ClientID = "your-application-id-here" +``` + +### Option 2: Pass ClientID as Parameter +Run the script with your ClientID: +```powershell +.\WinGet-WrapperImportFromCSV.ps1 -TenantID "yourtenant.onmicrosoft.com" -ClientID "your-application-id" -csvFile "your-csv-file.csv" +``` + +## Troubleshooting + +### Common Issues + +1. "No reply address is registered for the application" + - **Cause**: Missing redirect URI configuration + - **Solution**: Follow Step 2 in the configuration process + +2. "Application is not authorized to perform this operation" + - **Cause**: Missing or unauthorized API permissions + - **Solution**: Ensure Step 3 is completed and admin consent is granted + +3. "AADSTS700016" or "AADSTS90099" + - **Cause**: Application not properly authorized in tenant + - **Solution**: Ensure admin consent is granted and the account has proper roles (Global Admin or Intune Administrator) + +## Best Practices + +1. **Security**: + - Regularly review and audit application permissions + - Use separate applications for development and production + - Follow the principle of least privilege when assigning permissions + +2. **Maintenance**: + - Document your application ID and configuration + - Regularly review and update permissions as needed + - Monitor application usage through Azure AD audit logs + +## Required Azure AD Roles + +The user account running the scripts needs one of these roles: +- Intune Administrator +- Global Administrator + +## Additional Resources + +- [Microsoft Graph Permissions Reference](https://docs.microsoft.com/en-us/graph/permissions-reference) +- [Azure AD Application Registration](https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app) +- [Microsoft Graph PowerShell Authentication](https://docs.microsoft.com/en-us/powershell/microsoftgraph/authentication-commands) + + + +see https://github.com/SorenLundt/WinGet-Wrapper/issues/21 +see https://github.com/SorenLundt/WinGet-Wrapper/pull/23 \ No newline at end of file diff --git a/WinGet-WrapperImportFromCSV.ps1 b/WinGet-WrapperImportFromCSV.ps1 index 0d0bfbe..41e62a1 100644 --- a/WinGet-WrapperImportFromCSV.ps1 +++ b/WinGet-WrapperImportFromCSV.ps1 @@ -48,8 +48,12 @@ Param ( [Parameter(Mandatory = $False)] [string]$ClientID = "14d82eec-204b-4c2f-b7e8-296a70dab67e", + #Redirect URI of Enterprise application + [Parameter(Mandatory = $False)] + [string]$RedirectURL = "https://login.microsoftonline.com/common/oauth2/nativeclient", + #TenantID to connect to MSGraph/InTune - [Parameter(Mandatory=$True)] + [Parameter(Mandatory = $True)] [string]$TenantID, #LogFile (Manually define logfile path. If not defined, default will be used) @@ -66,11 +70,11 @@ Param ( ) #Timestamp -$TimeStamp = Get-Date -Format "yyyy-MM-dd_HH-mm-ss" +$TimeStamp = Get-Date -Format 'yyyy-MM-dd_HH-mm-ss' # Default Log File if (-not $LogFile) { - $LogFolder = Join-Path -Path $PSScriptRoot -ChildPath "Logs" + $LogFolder = Join-Path -Path $PSScriptRoot -ChildPath 'Logs' # Create logs folder if it doesn't exist if (-not (Test-Path -Path $LogFolder)) { @@ -86,7 +90,7 @@ function Write-Log { [string]$LogFile = "$LogFile" ) - $LogMsgTimeStamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" + $LogMsgTimeStamp = Get-Date -Format 'yyyy-MM-dd HH:mm:ss' $LogEntry = "[$LogMsgTimeStamp] $Message" # Output to the console @@ -101,63 +105,68 @@ Write-log "Parameters: csvFile: $csvFile, TenantID: $TenantID, SkipConfirmation: # Install and load required modules # https://github.com/MSEndpointMgr/IntuneWin32App -if (-not $SkipModuleCheck){ -$intuneWin32AppModule = "IntuneWin32App" -$microsoftGraphIntuneModule = "Microsoft.Graph.Intune" - -# Check if update is required for IntuneWin32App module -$moduleInstalled = Get-InstalledModule -Name $intuneWin32AppModule -ErrorAction SilentlyContinue - -if (-not $moduleInstalled) { - Install-Module -Name $intuneWin32AppModule -Force -} else { - $latestVersion = (Find-Module -Name $intuneWin32AppModule).Version - if ($moduleInstalled.Version -lt $latestVersion) { - Update-Module -Name $intuneWin32AppModule -Force - } else { - Write-Host "Module $intuneWin32AppModule is already up-to-date." +if (-not $SkipModuleCheck) { + $intuneWin32AppModule = 'IntuneWin32App' + $microsoftGraphIntuneModule = 'Microsoft.Graph.Intune' + + # Check if update is required for IntuneWin32App module + $moduleInstalled = Get-InstalledModule -Name $intuneWin32AppModule -ErrorAction SilentlyContinue + + if (-not $moduleInstalled) { + Install-Module -Name $intuneWin32AppModule -Force + } + else { + $latestVersion = (Find-Module -Name $intuneWin32AppModule).Version + if ($moduleInstalled.Version -lt $latestVersion) { + Update-Module -Name $intuneWin32AppModule -Force + } + else { + Write-Host "Module $intuneWin32AppModule is already up-to-date." + } } -} -# Check if update is required for Microsoft.Graph.Intune module -$moduleInstalled = Get-InstalledModule -Name $microsoftGraphIntuneModule -ErrorAction SilentlyContinue - -if (-not $moduleInstalled) { - Install-Module -Name $microsoftGraphIntuneModule -Force -} else { - $latestVersion = (Find-Module -Name $microsoftGraphIntuneModule).Version - if ($moduleInstalled.Version -lt $latestVersion) { - Update-Module -Name $microsoftGraphIntuneModule -Force - } else { - Write-Host "Module $microsoftGraphIntuneModule is already up-to-date." + # Check if update is required for Microsoft.Graph.Intune module + $moduleInstalled = Get-InstalledModule -Name $microsoftGraphIntuneModule -ErrorAction SilentlyContinue + + if (-not $moduleInstalled) { + Install-Module -Name $microsoftGraphIntuneModule -Force + } + else { + $latestVersion = (Find-Module -Name $microsoftGraphIntuneModule).Version + if ($moduleInstalled.Version -lt $latestVersion) { + Update-Module -Name $microsoftGraphIntuneModule -Force + } + else { + Write-Host "Module $microsoftGraphIntuneModule is already up-to-date." + } } -} } #Import modules -Import-Module -Name "IntuneWin32App" -Import-Module -Name "Microsoft.Graph.Intune" +Import-Module -Name 'IntuneWin32App' +Import-Module -Name 'Microsoft.Graph.Intune' # Welcome greeting -Write-Log " " -Write-Log " " -Write-Log "-----------------------------" -Write-Log "---- WinGet-WrapperCreate----" -Write-Log "-----------------------------" -Write-Log " " -Write-Log " " -Write-Log "https://github.com/SorenLundt/WinGet-Wrapper" -Write-Log " GNU General Public License v3" +Write-Log ' ' +Write-Log ' ' +Write-Log '-----------------------------' +Write-Log '---- WinGet-WrapperCreate----' +Write-Log '-----------------------------' +Write-Log ' ' +Write-Log ' ' +Write-Log 'https://github.com/SorenLundt/WinGet-Wrapper' +Write-Log ' GNU General Public License v3' # Test CSV path if (Test-Path -Path "$csvFile" -PathType Leaf) { Write-Log "File: $csvFile" -} else { - Write-Log "File not found: $csvFile" -ForegroundColor "Red" +} +else { + Write-Log "File not found: $csvFile" -ForegroundColor 'Red' return } # Import the CSV file with custom headers -$data = Import-Csv -Path "$csvFile" -Header "PackageID", "Context", "AcceptNewerVersion", "UpdateOnly", "TargetVersion", "StopProcessInstall", "StopProcessUninstall", "PreScriptInstall", "PostScriptInstall", "PreScriptUninstall", "PostScriptUninstall", "CustomArgumentListInstall", "CustomArgumentListUninstall", "InstallIntent", "Notification", "GroupID" | Select-Object -Skip 1 +$data = Import-Csv -Path "$csvFile" -Header 'PackageID', 'Context', 'AcceptNewerVersion', 'UpdateOnly', 'TargetVersion', 'StopProcessInstall', 'StopProcessUninstall', 'PreScriptInstall', 'PostScriptInstall', 'PreScriptUninstall', 'PostScriptUninstall', 'CustomArgumentListInstall', 'CustomArgumentListUninstall', 'InstallIntent', 'Notification', 'GroupID' | Select-Object -Skip 1 # Convert "AcceptNewerVersion" and "UpdateOnly" columns to Boolean values $data = $data | ForEach-Object { @@ -165,27 +174,26 @@ $data = $data | ForEach-Object { $_.UpdateOnly = [bool]($_.UpdateOnly -as [int]) $_ } -Write-Log "-- IMPORT LIST --" -foreach ($row in $data){ +Write-Log '-- IMPORT LIST --' +foreach ($row in $data) { Write-Log "IMPORT PackageID:$($row.PackageID) - Context:$($row.Context) - UpdateOnly:$($row.UpdateOnly) - TargetVersion:$($row.TargetVersion)" -ForegroundColor Gray } -Write-Log "" +Write-Log '' -Write-Log "-- DEPLOY LIST --" -foreach ($row in $data){ - if ($null = $row.GroupID -or $row.GroupID -ne "") - { +Write-Log '-- DEPLOY LIST --' +foreach ($row in $data) { + if ($null = $row.GroupID -or $row.GroupID -ne '') { Write-Log "DEPLOY PackageID:$($row.PackageID) GroupID:$($row.GroupID) InstallIntent:$($row.InstallIntent) Notification:$($row.Notification)" -ForegroundColor Gray } } #Connect to Intune #if (-not $SkipInTuneConnection){ -try{ -Connect-MSIntuneGraph -TenantID "$TenantID" -ClientID $ClientID -Interactive +try { + Connect-MSIntuneGraph -TenantID "$TenantID" -ClientID $ClientID -RedirectUri $RedirectURL -Interactive } catch { - Write-Log "ERROR: Connect-MSIntuneGraph Failed. Exiting" -ForegroundColor "Red" + Write-Log 'ERROR: Connect-MSIntuneGraph Failed. Exiting' -ForegroundColor 'Red' break } #} @@ -193,92 +201,89 @@ catch { #Import each application to InTune foreach ($row in $data) { -& { - try{ -#Write-Log "--- Package Details ---" -#Write-Log "PackageID: $($row.PackageID)" -#Write-Log "Context: $($row.Context)" -#Write-Log "AcceptNewerVersion: $($row.AcceptNewerVersion)" -#Write-Log "UpdateOnly: $($row.UpdateOnly)" -#Write-Log "TargetVersion: $($row.TargetVersion)" -#Write-Log "StopProcessInstall: $($row.StopProcessInstall)" -#Write-Log "StopProcessUninstall: $($row.StopProcessUninstall)" -#Write-Log "PreScriptInstall: $($row.PreScriptInstall)" -#Write-Log "PostScriptInstall: $($row.PostScriptInstall)" -#Write-Log "PreScriptUninstall: $($row.PreScriptUninstall)" -#Write-Log "PostScriptUninstall: $($row.PostScriptUninstall)" -#Write-Log "CustomArgumentListInstall: $($row.CustomArgumentListInstall)" -#Write-Log "CustomArgumentListInstall: $($row.CustomArgumentListUninstall)" - -#TimeStamp -$Timestamp = (Get-Date).ToString("yyyyMMddHHmmss") - -#Get User -$currentUser = $env:USERNAME - -Write-Log "--- Validation Start ---" -Write-Log "Validating Package $($row.PackageID)" -#Check context is valid -if ($row.Context -notin @("Machine", "machine", "User", "user")) { - Write-Log "Invalid context setting $($row.Context) for package $($row.PackageID) found in CSV. Please review the CSV. Exiting.." -ForegroundColor "Red" - break -} - -#Check AcceptNewerVersion is true or false -if ($row.AcceptNewerVersion -ne $True -and $row.AcceptNewerVersion -ne $False) -{ - Write-Log "Invalid AcceptNewerVersion setting $($row.AcceptNewerVersion) for package $($row.PackageID) found in CSV. Please review the CSV. Exiting.." -ForegroundColor "Red" - break -} - -#Check InstallIntent is valid -if ($null -ne $row.InstallIntent -and $row.InstallIntent -ne "") { - if ($row.InstallIntent -notcontains "Required" -and $row.InstallIntent -notcontains "required" -and $row.InstallIntent -notcontains "Available" -and $row.InstallIntent -notcontains "available") - { - Write-Log "Invalid InstallIntent setting $($row.InstallIntent) for package $($row.PackageID) found in CSV. Please review CSV (Use Available or Required) Exiting.." -ForegroundColor "Red" - break - } -} - -#Check Notification is valid -if ($null -ne $row.Notification -and $row.Notification -ne "") { - $validNotificationValues = "showAll", "showReboot", "hideAll" - if ($validNotificationValues -notcontains $row.Notification.ToLower()) { - Write-Log "Invalid Notification setting $($row.Notification) for package $($row.PackageID) found in CSV. Please review CSV (Use showAll, showReboot, or hideAll) Exiting.." -ForegroundColor "Red" - break - } -} - -#Check GroupID is set if InstallIntent is specified -if ($null -ne $row.InstallIntent -and $row.InstallIntent -ne "") { - if ($row.GroupID -eq $null -or $row.GroupID -eq "") { - Write-Log "Invalid GroupID setting $($row.GroupID) for package $($row.PackageID) found in CSV. Please review CSV. If InstallIntent is set, GroupID must be set too!" - break - } -} - -#Check UpdateOnly is true or false -Write-Log "Checking UpdateOnly Value for $($row.PackageID)" -if ($row.UpdateOnly -ne $True -and $row.UpdateOnly -ne $False) -{ - Write-Log "Invalid UpdateOnly setting $($row.UpdateOnly) for package $($row.PackageID) found in CSV. Please review the CSV. Exiting.." -ForegroundColor "Red" - break -} - -#Check StopProcessInstall and StopProcessUninstall does not contain "exe" (inform should not contain .exe) -Write-Log "Checking StopProcessInstall Value for $($row.PackageID)" -if ($row.StopProcessInstall -contains ".") { - Write-Log "Invalid StopProcessInstall setting $($row.StopProcessInstall) for package $($row.PackageID) found in CSV. Please review the CSV. Exiting.." -ForegroundColor "Red" - break -} -Write-Log "Checking StopProcessUninstall Value for $($row.PackageID)" -if ($row.StopProcessUninstall -contains ".") { - Write-Log "Invalid StopProcessUninstall setting $($row.StopProcessUninstall) for package $($row.PackageID) found in CSV. Please review the CSV. Exiting.." -ForegroundColor "Red" - break -} - -#Check PreScriptInstall, PostScriptInstall, PreScriptUninstall, PostScriptUninstall contains .ps1 (inform must be .ps1) -<# + & { + try { + #Write-Log "--- Package Details ---" + #Write-Log "PackageID: $($row.PackageID)" + #Write-Log "Context: $($row.Context)" + #Write-Log "AcceptNewerVersion: $($row.AcceptNewerVersion)" + #Write-Log "UpdateOnly: $($row.UpdateOnly)" + #Write-Log "TargetVersion: $($row.TargetVersion)" + #Write-Log "StopProcessInstall: $($row.StopProcessInstall)" + #Write-Log "StopProcessUninstall: $($row.StopProcessUninstall)" + #Write-Log "PreScriptInstall: $($row.PreScriptInstall)" + #Write-Log "PostScriptInstall: $($row.PostScriptInstall)" + #Write-Log "PreScriptUninstall: $($row.PreScriptUninstall)" + #Write-Log "PostScriptUninstall: $($row.PostScriptUninstall)" + #Write-Log "CustomArgumentListInstall: $($row.CustomArgumentListInstall)" + #Write-Log "CustomArgumentListInstall: $($row.CustomArgumentListUninstall)" + + #TimeStamp + $Timestamp = (Get-Date).ToString('yyyyMMddHHmmss') + + #Get User + $currentUser = $env:USERNAME + + Write-Log '--- Validation Start ---' + Write-Log "Validating Package $($row.PackageID)" + #Check context is valid + if ($row.Context -notin @('Machine', 'machine', 'User', 'user')) { + Write-Log "Invalid context setting $($row.Context) for package $($row.PackageID) found in CSV. Please review the CSV. Exiting.." -ForegroundColor 'Red' + break + } + + #Check AcceptNewerVersion is true or false + if ($row.AcceptNewerVersion -ne $True -and $row.AcceptNewerVersion -ne $False) { + Write-Log "Invalid AcceptNewerVersion setting $($row.AcceptNewerVersion) for package $($row.PackageID) found in CSV. Please review the CSV. Exiting.." -ForegroundColor 'Red' + break + } + + #Check InstallIntent is valid + if ($null -ne $row.InstallIntent -and $row.InstallIntent -ne '') { + if ($row.InstallIntent -notcontains 'Required' -and $row.InstallIntent -notcontains 'required' -and $row.InstallIntent -notcontains 'Available' -and $row.InstallIntent -notcontains 'available') { + Write-Log "Invalid InstallIntent setting $($row.InstallIntent) for package $($row.PackageID) found in CSV. Please review CSV (Use Available or Required) Exiting.." -ForegroundColor 'Red' + break + } + } + + #Check Notification is valid + if ($null -ne $row.Notification -and $row.Notification -ne '') { + $validNotificationValues = 'showAll', 'showReboot', 'hideAll' + if ($validNotificationValues -notcontains $row.Notification.ToLower()) { + Write-Log "Invalid Notification setting $($row.Notification) for package $($row.PackageID) found in CSV. Please review CSV (Use showAll, showReboot, or hideAll) Exiting.." -ForegroundColor 'Red' + break + } + } + + #Check GroupID is set if InstallIntent is specified + if ($null -ne $row.InstallIntent -and $row.InstallIntent -ne '') { + if ($row.GroupID -eq $null -or $row.GroupID -eq '') { + Write-Log "Invalid GroupID setting $($row.GroupID) for package $($row.PackageID) found in CSV. Please review CSV. If InstallIntent is set, GroupID must be set too!" + break + } + } + + #Check UpdateOnly is true or false + Write-Log "Checking UpdateOnly Value for $($row.PackageID)" + if ($row.UpdateOnly -ne $True -and $row.UpdateOnly -ne $False) { + Write-Log "Invalid UpdateOnly setting $($row.UpdateOnly) for package $($row.PackageID) found in CSV. Please review the CSV. Exiting.." -ForegroundColor 'Red' + break + } + + #Check StopProcessInstall and StopProcessUninstall does not contain "exe" (inform should not contain .exe) + Write-Log "Checking StopProcessInstall Value for $($row.PackageID)" + if ($row.StopProcessInstall -contains '.') { + Write-Log "Invalid StopProcessInstall setting $($row.StopProcessInstall) for package $($row.PackageID) found in CSV. Please review the CSV. Exiting.." -ForegroundColor 'Red' + break + } + Write-Log "Checking StopProcessUninstall Value for $($row.PackageID)" + if ($row.StopProcessUninstall -contains '.') { + Write-Log "Invalid StopProcessUninstall setting $($row.StopProcessUninstall) for package $($row.PackageID) found in CSV. Please review the CSV. Exiting.." -ForegroundColor 'Red' + break + } + + #Check PreScriptInstall, PostScriptInstall, PreScriptUninstall, PostScriptUninstall contains .ps1 (inform must be .ps1) + <# if ( ($null -ne $row.PreScriptInstall -and -not [string]::IsNullOrEmpty($row.PreScriptInstall)) -or ($null -ne $row.PostScriptInstall -and -not [string]::IsNullOrEmpty($row.PostScriptInstall)) -or @@ -297,452 +302,458 @@ if ( } #> -#Print CustomArgumentListInstall if set and wait confirm -Write-Log "Checking CustomArgumentListInstall Value for $($row.PackageID)" -if ($row.CustomArgumentListInstall -ne "" -or $null) -{ - Write-Log "-- CustomArgumentListInstall --" - Write-Log "$($row.CustomArgumentListInstall)" - if (!$SkipConfirmation) { - $confirmation = Read-Host "Please confirm CustomArgumentListInstall ($PackageID)? (Y/N)" - - if ($confirmation -eq "Y" -or $confirmation -eq "y") { - Write-Log "Confirmed" - } else { - Write-Log "CustomArgumentListInstall not confirmed. Exiting.." - return - } -} -} - -#Print CustomArgumentListUninstall if set and wait confirm -Write-Log "Checking CustomArgumentListUninstall Value for $($row.PackageID)" -if ($row.CustomArgumentListUninstall -ne "" -or $null) -{ - Write-Log "-- CustomArgumentListUninstall --" - Write-Log "$($row.CustomArgumentListUninstall)" - if (!$SkipConfirmation) { - $confirmation = Read-Host "Please confirm CustomArgumentListUninstall ($PackageID)? (Y/N)" - - if ($confirmation -eq "Y" -or $confirmation -eq "y") { - Write-Log "Confirmed" - } else { - Write-Log "CustomArgumentListUninstall not confirmed. Exiting.." - return - } -} -} - -Write-Log "Finished Validation for $($row.PackageID)" -Write-Log "--- Validation End ---" -Write-Log "" - -#Print Package details and wait for confirmation. If package not found break. -$PackageIDOutLines = @(winget show --exact --id $($row.PackageID) --scope $($row.Context) --accept-source-agreements) -#Check if targetversion specified -if ($null -ne $row.TargetVersion -and $row.TargetVersion -ne "") -{ - $PackageIDOutLines = @(winget show --exact --id $($row.PackageID) --scope $($row.Context) --version $($row.TargetVersion) --accept-source-agreements) -} -$PackageIDout = $PackageIDOutLines -join "`r`n" - -if ($PackageIDOutLines -notcontains "No package found matching input criteria.") { - if ($PackageIDOutLines -notcontains " No applicable installer found; see logs for more details.") { - if (!$SkipConfirmation) { - Write-Log "--- WINGET PACKAGE INFORMATION ---" - Write-Log $PackageIDOut - Write-Log "--------------------------" - $confirmation = Read-Host "Confirm the package details above (Y/N)" - if ($confirmation -eq "N" -or $confirmation -eq "N") { - break - } - } - } else { - # Second condition not met - Write-Log "Applicable installer not found for $($row.Context) context" -ForegroundColor "Red" - $imported = $False - $row | Add-Member -MemberType NoteProperty -Name "Imported" -Value $imported #Write imported status to $row - $errortext = "Applicable installer not found for $($row.Context) context" - $row | Add-Member -MemberType NoteProperty -Name "ErrorText" -Value $errortext #Write errortext to $row - continue - } -} else { - Write-Log "Package $($row.PackageID) not found using winget" -ForegroundColor "Red" - return -} - - -#Scrape Winget package details to use in InTune from $PackageIDOut -#Scrape "Found " Scrape all line from after this -#Scrape "Description" Regex.. Find "Description: " Scrape all line from after this - -#Clear variables -$variables = "PackageName", "Version", "Publisher", "PublisherURL", "PublisherSupportURL", "Author", "Description", "Homepage", "License", "LicenseURL", "Copyright", "CopyrightURL", "InstallerType", "InstallerLocale", "InstallerURL", "InstallerSHA256" -Remove-Variable -Name $variables -ErrorAction SilentlyContinue - -# Use regular expressions to extract details -$PackageName = $PackageIDOut | Select-String -Pattern "Found (.+)" | ForEach-Object { $_.Matches.Groups[1].Value } -$PackageName = $PackageName -replace "\[", "(" -replace "\]", ")" #Clean Packagename replace [] with () -$Version = $PackageIDOut | Select-String -Pattern "Version: (.+)" | ForEach-Object { $_.Matches.Groups[1].Value } -$Publisher = $PackageIDOut | Select-String -Pattern "Publisher: (.+)" | ForEach-Object { $_.Matches.Groups[1].Value } -$PublisherURL = $PackageIDOut | Select-String -Pattern "Publisher Url: (.+)" | ForEach-Object { $_.Matches.Groups[1].Value } -$PublisherSupportURL = $PackageIDOut | Select-String -Pattern "Publisher Support Url: (.+)" | ForEach-Object { $_.Matches.Groups[1].Value } -$Author = $PackageIDOut | Select-String -Pattern "Author: (.+)" | ForEach-Object { $_.Matches.Groups[1].Value } -$Description = $PackageIDOut | Select-String -Pattern "Description: (.+)" | ForEach-Object { $_.Matches.Groups[1].Value } -$Homepage = $PackageIDOut | Select-String -Pattern "Homepage: (.+)" | ForEach-Object { $_.Matches.Groups[1].Value } -$License = $PackageIDOut | Select-String -Pattern "License: (.+)" | ForEach-Object { $_.Matches.Groups[1].Value } -$LicenseURL = $PackageIDOut | Select-String -Pattern "License Url: (.+)" | ForEach-Object { $_.Matches.Groups[1].Value } -$Copyright = $PackageIDOut | Select-String -Pattern "Copyright: (.+)" | ForEach-Object { $_.Matches.Groups[1].Value } -$CopyrightURL = $PackageIDOut | Select-String -Pattern "Copyright Url: (.+)" | ForEach-Object { $_.Matches.Groups[1].Value } - -# Extract Installer details -$InstallerType = $PackageIDOut | Select-String -Pattern "Installer Type: (.+)" | ForEach-Object { $_.Matches.Groups[1].Value } -$InstallerLocale = $PackageIDOut | Select-String -Pattern "Installer Locale: (.+)" | ForEach-Object { $_.Matches.Groups[1].Value } -$InstallerURL = $PackageIDOut | Select-String -Pattern "Installer Url: (.+)" | ForEach-Object { $_.Matches.Groups[1].Value } -$InstallerSHA256 = $PackageIDOut | Select-String -Pattern "Installer SHA256: (.+)" | ForEach-Object { $_.Matches.Groups[1].Value } - -# Loop through the variable names and assign "None" if empty or null (Avoid script issues) -foreach ($variable in $variables) { - if ($null -eq (Get-Variable -Name $variable -ValueOnly)) { - Set-Variable -Name $variable -Value "None" - } -} - -# Display the extracted variables -Write-Log "" -Write-Log "--- WinGet Scraped Metadata $($row.PackageID) ---" -Write-Log "PackageName: $PackageName" -Write-Log "Version: $Version" -Write-Log "Publisher: $Publisher" -Write-Log "PublisherURL: $PublisherURL" -Write-Log "PublisherSupportURL: $PublisherSupportURL" -Write-Log "Author: $Author" -Write-Log "Description: $Description" -Write-Log "Homepage: $Homepage" -Write-Log "License: $License" -Write-Log "LicenseURL: $LicenseURL" -Write-Log "Copyright: $Copyright" -Write-Log "CopyrightURL: $CopyrightURL" -Write-Log "InstallerType: $InstallerType" -Write-Log "InstallerLocale: $InstallerLocale" -Write-Log "InstallerURL: $InstallerURL" -Write-Log "InstallerSHA256: $InstallerSHA256" -Write-Log "" -Write-Log "--------------------------" - -# Build package details to prepare InTune import -$PackageName += " ($($row.Context))" -if ($Row.TargetVersion -ne $null){ - $PackageName += " $($row.TargetVersion)" -} - -$PackageName += " (WinGet)" - -if ($Row.UpdateOnly -eq $true){ - $PackageName = "Update for " + $PackageName -} - -#Clear ArgumentList and CommandLine parameters. -Remove-Variable -Name ArgumentListInstall, ArgumentListUninstall, InstallCommandLine, UninstallCommandLine -ErrorAction SilentlyContinue - -#Build ArgumentListInstall (if no custom argumentlist set) -if ([string]::IsNullOrEmpty($row.CustomArgumentListInstall)) { -$ArgumentListInstall = "install --exact --id $($row.PackageID) --silent --accept-package-agreements --accept-source-agreements --scope $($row.Context)" -if ($Row.TargetVersion -ne $null -and $Row.TargetVersion -ne "") { -$ArgumentListInstall += " --version $($Row.TargetVersion)" -} -} -else { - $ArgumentListInstall = $row.CustomArgumentListInstall -} -#Replace first 7 characters of ArgumentListInstall with "update" if package is UpdateOnly -if ($Row.UpdateOnly -eq $true) -{ - $ArgumentListInstall = "update" + $ArgumentListInstall.Substring(7) -} - -#Build ArgumentListUninstall (if no custom argumentlist set) -if ([string]::IsNullOrEmpty($row.CustomArgumentListUninstall)) { -$ArgumentListUninstall = "uninstall --exact --id $($row.PackageID) --silent --accept-source-agreements --scope $($row.Context)" -if ($Row.TargetVersion -ne $null -and $Row.TargetVersion -ne "") { -$ArgumentListUninstall += " --version $($Row.TargetVersion)" -} -} -else { - $ArgumentListUninstall = $row.CustomArgumentListUninstall -} - - -# Build install commandline -$InstallCommandLine = "Powershell.exe -NoLogo -NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass -File WinGet-Wrapper.ps1 -PackageName $($row.PackageID) -ArgumentList "+[char]34+"$ArgumentListInstall"+[char]34 -if ($row.StopProcessInstall -ne $null -and $row.StopProcessInstall -ne ""){ - $InstallCommandLine += " -StopProcess '$($row.StopProcessInstall)'" -} -if ($row.PreScriptInstall -ne $null -and $row.PreScriptInstall -ne ""){ - $InstallCommandLine += " -Prescript '$($row.PreScriptInstall)'" -} - -if ($row.PostScriptInstall -ne $null -and $row.PostScriptInstall -ne "") { - $InstallCommandLine += " -Postscript '$($row.PostScriptInstall)'" -} - -# Build uninstall commandline -$UninstallCommandLine = "Powershell.exe -NoLogo -NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass -File WinGet-Wrapper.ps1 -PackageName $($row.PackageID) -ArgumentList "+[char]34+"$ArgumentListUninstall"+[char]34 -if ($row.StopProcessUninstall -ne $null -and $row.StopProcessUninstall -ne ""){ - $UninstallCommandLine += " -StopProcess '$($row.StopProcessUninstall)'" -} - -if ($row.PreScriptUninstall -ne $null -and $row.PreScriptUninstall -ne "") { - $InstallCommandLine += " -PreUninstall '$($row.PreScriptUninstall)'" -} - -if ($row.PostScriptUninstall -ne $null -and $row.PostScriptUninstall -ne "") { - $InstallCommandLine += " -PostUninstall '$($row.PostScriptUninstall)'" -} - -Write-Log " " -Write-Log "--InstallCommandLine--" -Write-Log "$InstallCommandLine" -Write-Log " " -Write-Log "--UninstallCommandLine--" -Write-Log "$UninstallCommandLine" -Write-Log " " - -#Make folder to store script files - -#Find script root - set $currentDirectory -if ($scriptRoot){ - $currentDirectory = $scriptRoot } -else { - $currentDirectory = $PSScriptRoot} - -write-log "currentDirectory: $currentDirectory" -write-log "scriptRoot: $scriptRoot" -write-log "PSScriptRoot: $PSScriptRoot" -write-log "csvFile: $csvFile" -write-log "LogFile: $LogFile" -write-log "TenantID: $TenantID" -write-log "SkipConfirmation: $SkipConfirmation" -write-log "SkipInTuneConnection: $SkipInTuneConnection" -write-log "SkipModuleCheck: $SkipModuleCheck" -# Log the retrieval of variables using Get-Variable -$variables = Get-Variable -foreach ($variable in $variables) { - Write-Output "Retrieving variable: $($variable.Name) = $($variable.Value)" -} - -# Generate foldername -$folderName = "$($Row.PackageID)" -$folderName += "-$($Row.Context)" - -if ($Row.UpdateOnly -eq $True) { - $folderName += "-UpdateOnly" -} - -if ($Row.TargetVersion -ne $null -and $Row.TargetVersion -ne "") { - $folderName += "-V$($Row.TargetVersion)" -} - -$folderName += "-$currentUser-$Timestamp" - -# Combine the current directory and "packages" to create the full "Packages" directory path -$packagesDirectory = Join-Path -Path $currentDirectory -ChildPath "Packages" - -# Check if the "packages" directory exists, and if not, create it -if (-Not (Test-Path -Path $packagesDirectory)) { - New-Item -Path $packagesDirectory -ItemType Directory | Out-Null -} - -# Combine the "Packages" directory path with the folder name to create the full path -$PackageFolderPath = Join-Path -Path $packagesDirectory -ChildPath $folderName - -# Create the subfolder with the desired name -New-Item -Path $PackageFolderPath -ItemType Directory | Out-Null - -Write-Log "Local Package Data Location: $PackageFolderPath" - -#Build DetectionScript -$WingetDetectionScriptSource = "$currentDirectory\WinGet-WrapperDetection.ps1" -$WingetDetectionScriptDestination = "$PackageFolderPath\WinGet-WrapperDetection-$($Row.PackageID).ps1" - -# Copy the source script to the destination -Copy-Item -Path $WingetDetectionScriptSource -Destination $WingetDetectionScriptDestination - -# Read the destination script -$scriptContent = Get-Content -Path $WingetDetectionScriptDestination - -# Identify the start and end of the # Settings section -$startPattern = "# Settings" -$endPattern = "# EndSettings" - -# Join the script content into a single string -$scriptText = [string]::Join([Environment]::NewLine, $scriptContent) - -# Check if the # Settings section is present -if ($scriptText -match "(?s)$startPattern.*?$endPattern") { - $settingsSection = $Matches[0] # Extract the # Settings section - -# If $Row.AcceptNewerVersion is $True, replace "$True" with "$True" -if ($Row.AcceptNewerVersion -eq $True) { - $settingsSection = $settingsSection -replace '"\$True"','$True' -} -# If $Row.AcceptNewerVersion is $False, replace "$True" with "$False" -elseif ($Row.AcceptNewerVersion -eq $False) { - $settingsSection = $settingsSection -replace '"\$True"','$False' -} - - # Replace "Exact WinGet Package ID" with the actual value of $PackageID within the # Settings section - $settingsSection = $settingsSection -replace "Exact WinGet Package ID", $Row.PackageID - - # If $TargetVersion is not null or not empty, replace "TargetVersion = ''" with "TargetVersion = '$TargetVersion'" within the # Settings section - if ($row.TargetVersion -ne $null -and $row.TargetVersion -ne "") { - $settingsSection = $settingsSection -replace 'TargetVersion = ""', "TargetVersion = ""$($Row.TargetVersion)""" - } - - # Replace the updated # Settings section in the script content - $scriptText = $scriptText -replace "(?s)$startPattern.*?$endPattern", $settingsSection - - # Save the updated script content - Set-Content -Path $WingetDetectionScriptDestination -Value $scriptText - - Write-Log "Detection Script complete. $WingetDetectionScriptDestination" -} else { - Write-Log "The # Settings section was not found in the script." -ForegroundColor "Red" -} - - -#Build RequirementScript -if ($Row.UpdateOnly -eq $True){ - $WingetRequirementScriptSource = "$currentDirectory\Winget-WrapperRequirements.ps1" - $WingetRequirementScriptDestination = "$PackageFolderPath\WinGet-WrapperRequirements-$($Row.PackageID).ps1" + #Print CustomArgumentListInstall if set and wait confirm + Write-Log "Checking CustomArgumentListInstall Value for $($row.PackageID)" + if ($row.CustomArgumentListInstall -ne '' -or $null) { + Write-Log '-- CustomArgumentListInstall --' + Write-Log "$($row.CustomArgumentListInstall)" + if (!$SkipConfirmation) { + $confirmation = Read-Host "Please confirm CustomArgumentListInstall ($PackageID)? (Y/N)" + + if ($confirmation -eq 'Y' -or $confirmation -eq 'y') { + Write-Log 'Confirmed' + } + else { + Write-Log 'CustomArgumentListInstall not confirmed. Exiting..' + return + } + } + } + + #Print CustomArgumentListUninstall if set and wait confirm + Write-Log "Checking CustomArgumentListUninstall Value for $($row.PackageID)" + if ($row.CustomArgumentListUninstall -ne '' -or $null) { + Write-Log '-- CustomArgumentListUninstall --' + Write-Log "$($row.CustomArgumentListUninstall)" + if (!$SkipConfirmation) { + $confirmation = Read-Host "Please confirm CustomArgumentListUninstall ($PackageID)? (Y/N)" + + if ($confirmation -eq 'Y' -or $confirmation -eq 'y') { + Write-Log 'Confirmed' + } + else { + Write-Log 'CustomArgumentListUninstall not confirmed. Exiting..' + return + } + } + } + + Write-Log "Finished Validation for $($row.PackageID)" + Write-Log '--- Validation End ---' + Write-Log '' + + #Print Package details and wait for confirmation. If package not found break. + $PackageIDOutLines = @(winget show --exact --id $($row.PackageID) --scope $($row.Context) --accept-source-agreements) + #Check if targetversion specified + if ($null -ne $row.TargetVersion -and $row.TargetVersion -ne '') { + $PackageIDOutLines = @(winget show --exact --id $($row.PackageID) --scope $($row.Context) --version $($row.TargetVersion) --accept-source-agreements) + } + $PackageIDout = $PackageIDOutLines -join "`r`n" + + if ($PackageIDOutLines -notcontains 'No package found matching input criteria.') { + if ($PackageIDOutLines -notcontains ' No applicable installer found; see logs for more details.') { + if (!$SkipConfirmation) { + Write-Log '--- WINGET PACKAGE INFORMATION ---' + Write-Log $PackageIDOut + Write-Log '--------------------------' + $confirmation = Read-Host 'Confirm the package details above (Y/N)' + if ($confirmation -eq 'N' -or $confirmation -eq 'N') { + break + } + } + } + else { + # Second condition not met + Write-Log "Applicable installer not found for $($row.Context) context" -ForegroundColor 'Red' + $imported = $False + $row | Add-Member -MemberType NoteProperty -Name 'Imported' -Value $imported #Write imported status to $row + $errortext = "Applicable installer not found for $($row.Context) context" + $row | Add-Member -MemberType NoteProperty -Name 'ErrorText' -Value $errortext #Write errortext to $row + continue + } + } + else { + Write-Log "Package $($row.PackageID) not found using winget" -ForegroundColor 'Red' + return + } + + + #Scrape Winget package details to use in InTune from $PackageIDOut + #Scrape "Found " Scrape all line from after this + #Scrape "Description" Regex.. Find "Description: " Scrape all line from after this + + #Clear variables + $variables = 'PackageName', 'Version', 'Publisher', 'PublisherURL', 'PublisherSupportURL', 'Author', 'Description', 'Homepage', 'License', 'LicenseURL', 'Copyright', 'CopyrightURL', 'InstallerType', 'InstallerLocale', 'InstallerURL', 'InstallerSHA256' + Remove-Variable -Name $variables -ErrorAction SilentlyContinue + + # Use regular expressions to extract details + $PackageName = $PackageIDOut | Select-String -Pattern 'Found (.+)' | ForEach-Object { $_.Matches.Groups[1].Value } + $PackageName = $PackageName -replace '\[', '(' -replace '\]', ')' #Clean Packagename replace [] with () + $Version = $PackageIDOut | Select-String -Pattern 'Version: (.+)' | ForEach-Object { $_.Matches.Groups[1].Value } + $Publisher = $PackageIDOut | Select-String -Pattern 'Publisher: (.+)' | ForEach-Object { $_.Matches.Groups[1].Value } + $PublisherURL = $PackageIDOut | Select-String -Pattern 'Publisher Url: (.+)' | ForEach-Object { $_.Matches.Groups[1].Value } + $PublisherSupportURL = $PackageIDOut | Select-String -Pattern 'Publisher Support Url: (.+)' | ForEach-Object { $_.Matches.Groups[1].Value } + $Author = $PackageIDOut | Select-String -Pattern 'Author: (.+)' | ForEach-Object { $_.Matches.Groups[1].Value } + $Description = $PackageIDOut | Select-String -Pattern 'Description: (.+)' | ForEach-Object { $_.Matches.Groups[1].Value } + $Homepage = $PackageIDOut | Select-String -Pattern 'Homepage: (.+)' | ForEach-Object { $_.Matches.Groups[1].Value } + $License = $PackageIDOut | Select-String -Pattern 'License: (.+)' | ForEach-Object { $_.Matches.Groups[1].Value } + $LicenseURL = $PackageIDOut | Select-String -Pattern 'License Url: (.+)' | ForEach-Object { $_.Matches.Groups[1].Value } + $Copyright = $PackageIDOut | Select-String -Pattern 'Copyright: (.+)' | ForEach-Object { $_.Matches.Groups[1].Value } + $CopyrightURL = $PackageIDOut | Select-String -Pattern 'Copyright Url: (.+)' | ForEach-Object { $_.Matches.Groups[1].Value } + + # Extract Installer details + $InstallerType = $PackageIDOut | Select-String -Pattern 'Installer Type: (.+)' | ForEach-Object { $_.Matches.Groups[1].Value } + $InstallerLocale = $PackageIDOut | Select-String -Pattern 'Installer Locale: (.+)' | ForEach-Object { $_.Matches.Groups[1].Value } + $InstallerURL = $PackageIDOut | Select-String -Pattern 'Installer Url: (.+)' | ForEach-Object { $_.Matches.Groups[1].Value } + $InstallerSHA256 = $PackageIDOut | Select-String -Pattern 'Installer SHA256: (.+)' | ForEach-Object { $_.Matches.Groups[1].Value } + + # Loop through the variable names and assign "None" if empty or null (Avoid script issues) + foreach ($variable in $variables) { + if ($null -eq (Get-Variable -Name $variable -ValueOnly)) { + Set-Variable -Name $variable -Value 'None' + } + } + + # Display the extracted variables + Write-Log '' + Write-Log "--- WinGet Scraped Metadata $($row.PackageID) ---" + Write-Log "PackageName: $PackageName" + Write-Log "Version: $Version" + Write-Log "Publisher: $Publisher" + Write-Log "PublisherURL: $PublisherURL" + Write-Log "PublisherSupportURL: $PublisherSupportURL" + Write-Log "Author: $Author" + Write-Log "Description: $Description" + Write-Log "Homepage: $Homepage" + Write-Log "License: $License" + Write-Log "LicenseURL: $LicenseURL" + Write-Log "Copyright: $Copyright" + Write-Log "CopyrightURL: $CopyrightURL" + Write-Log "InstallerType: $InstallerType" + Write-Log "InstallerLocale: $InstallerLocale" + Write-Log "InstallerURL: $InstallerURL" + Write-Log "InstallerSHA256: $InstallerSHA256" + Write-Log '' + Write-Log '--------------------------' + + # Build package details to prepare InTune import + $PackageName += " ($($row.Context))" + if ($Row.TargetVersion -ne $null) { + $PackageName += " $($row.TargetVersion)" + } + + $PackageName += ' (WinGet)' + + if ($Row.UpdateOnly -eq $true) { + $PackageName = 'Update for ' + $PackageName + } + + #Clear ArgumentList and CommandLine parameters. + Remove-Variable -Name ArgumentListInstall, ArgumentListUninstall, InstallCommandLine, UninstallCommandLine -ErrorAction SilentlyContinue + + #Build ArgumentListInstall (if no custom argumentlist set) + if ([string]::IsNullOrEmpty($row.CustomArgumentListInstall)) { + $ArgumentListInstall = "install --exact --id $($row.PackageID) --silent --accept-package-agreements --accept-source-agreements --scope $($row.Context)" + if ($Row.TargetVersion -ne $null -and $Row.TargetVersion -ne '') { + $ArgumentListInstall += " --version $($Row.TargetVersion)" + } + } + else { + $ArgumentListInstall = $row.CustomArgumentListInstall + } + #Replace first 7 characters of ArgumentListInstall with "update" if package is UpdateOnly + if ($Row.UpdateOnly -eq $true) { + $ArgumentListInstall = 'update' + $ArgumentListInstall.Substring(7) + } + + #Build ArgumentListUninstall (if no custom argumentlist set) + if ([string]::IsNullOrEmpty($row.CustomArgumentListUninstall)) { + $ArgumentListUninstall = "uninstall --exact --id $($row.PackageID) --silent --accept-source-agreements --scope $($row.Context)" + if ($Row.TargetVersion -ne $null -and $Row.TargetVersion -ne '') { + $ArgumentListUninstall += " --version $($Row.TargetVersion)" + } + } + else { + $ArgumentListUninstall = $row.CustomArgumentListUninstall + } + + + # Build install commandline + $InstallCommandLine = "Powershell.exe -NoLogo -NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass -File WinGet-Wrapper.ps1 -PackageName $($row.PackageID) -ArgumentList " + [char]34 + "$ArgumentListInstall" + [char]34 + if ($row.StopProcessInstall -ne $null -and $row.StopProcessInstall -ne '') { + $InstallCommandLine += " -StopProcess '$($row.StopProcessInstall)'" + } + if ($row.PreScriptInstall -ne $null -and $row.PreScriptInstall -ne '') { + $InstallCommandLine += " -Prescript '$($row.PreScriptInstall)'" + } + + if ($row.PostScriptInstall -ne $null -and $row.PostScriptInstall -ne '') { + $InstallCommandLine += " -Postscript '$($row.PostScriptInstall)'" + } + + # Build uninstall commandline + $UninstallCommandLine = "Powershell.exe -NoLogo -NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass -File WinGet-Wrapper.ps1 -PackageName $($row.PackageID) -ArgumentList " + [char]34 + "$ArgumentListUninstall" + [char]34 + if ($row.StopProcessUninstall -ne $null -and $row.StopProcessUninstall -ne '') { + $UninstallCommandLine += " -StopProcess '$($row.StopProcessUninstall)'" + } + + if ($row.PreScriptUninstall -ne $null -and $row.PreScriptUninstall -ne '') { + $InstallCommandLine += " -PreUninstall '$($row.PreScriptUninstall)'" + } + + if ($row.PostScriptUninstall -ne $null -and $row.PostScriptUninstall -ne '') { + $InstallCommandLine += " -PostUninstall '$($row.PostScriptUninstall)'" + } + + Write-Log ' ' + Write-Log '--InstallCommandLine--' + Write-Log "$InstallCommandLine" + Write-Log ' ' + Write-Log '--UninstallCommandLine--' + Write-Log "$UninstallCommandLine" + Write-Log ' ' + + #Make folder to store script files + + #Find script root - set $currentDirectory + if ($scriptRoot) { + $currentDirectory = $scriptRoot + } + else { + $currentDirectory = $PSScriptRoot + } + + write-log "currentDirectory: $currentDirectory" + write-log "scriptRoot: $scriptRoot" + write-log "PSScriptRoot: $PSScriptRoot" + write-log "csvFile: $csvFile" + write-log "LogFile: $LogFile" + write-log "TenantID: $TenantID" + write-log "SkipConfirmation: $SkipConfirmation" + write-log "SkipInTuneConnection: $SkipInTuneConnection" + write-log "SkipModuleCheck: $SkipModuleCheck" + # Log the retrieval of variables using Get-Variable + $variables = Get-Variable + foreach ($variable in $variables) { + Write-Output "Retrieving variable: $($variable.Name) = $($variable.Value)" + } + + # Generate foldername + $folderName = "$($Row.PackageID)" + $folderName += "-$($Row.Context)" + + if ($Row.UpdateOnly -eq $True) { + $folderName += '-UpdateOnly' + } + + if ($Row.TargetVersion -ne $null -and $Row.TargetVersion -ne '') { + $folderName += "-V$($Row.TargetVersion)" + } + + $folderName += "-$currentUser-$Timestamp" + + # Combine the current directory and "packages" to create the full "Packages" directory path + $packagesDirectory = Join-Path -Path $currentDirectory -ChildPath 'Packages' + + # Check if the "packages" directory exists, and if not, create it + if (-Not (Test-Path -Path $packagesDirectory)) { + New-Item -Path $packagesDirectory -ItemType Directory | Out-Null + } + + # Combine the "Packages" directory path with the folder name to create the full path + $PackageFolderPath = Join-Path -Path $packagesDirectory -ChildPath $folderName + + # Create the subfolder with the desired name + New-Item -Path $PackageFolderPath -ItemType Directory | Out-Null + + Write-Log "Local Package Data Location: $PackageFolderPath" + + #Build DetectionScript + $WingetDetectionScriptSource = "$currentDirectory\WinGet-WrapperDetection.ps1" + $WingetDetectionScriptDestination = "$PackageFolderPath\WinGet-WrapperDetection-$($Row.PackageID).ps1" + + # Copy the source script to the destination + Copy-Item -Path $WingetDetectionScriptSource -Destination $WingetDetectionScriptDestination + + # Read the destination script + $scriptContent = Get-Content -Path $WingetDetectionScriptDestination + + # Identify the start and end of the # Settings section + $startPattern = '# Settings' + $endPattern = '# EndSettings' + + # Join the script content into a single string + $scriptText = [string]::Join([Environment]::NewLine, $scriptContent) + + # Check if the # Settings section is present + if ($scriptText -match "(?s)$startPattern.*?$endPattern") { + $settingsSection = $Matches[0] # Extract the # Settings section + + # If $Row.AcceptNewerVersion is $True, replace "$True" with "$True" + if ($Row.AcceptNewerVersion -eq $True) { + $settingsSection = $settingsSection -replace '"\$True"', '$True' + } + # If $Row.AcceptNewerVersion is $False, replace "$True" with "$False" + elseif ($Row.AcceptNewerVersion -eq $False) { + $settingsSection = $settingsSection -replace '"\$True"', '$False' + } + + # Replace "Exact WinGet Package ID" with the actual value of $PackageID within the # Settings section + $settingsSection = $settingsSection -replace 'Exact WinGet Package ID', $Row.PackageID + + # If $TargetVersion is not null or not empty, replace "TargetVersion = ''" with "TargetVersion = '$TargetVersion'" within the # Settings section + if ($row.TargetVersion -ne $null -and $row.TargetVersion -ne '') { + $settingsSection = $settingsSection -replace 'TargetVersion = ""', "TargetVersion = ""$($Row.TargetVersion)""" + } + + # Replace the updated # Settings section in the script content + $scriptText = $scriptText -replace "(?s)$startPattern.*?$endPattern", $settingsSection + + # Save the updated script content + Set-Content -Path $WingetDetectionScriptDestination -Value $scriptText + + Write-Log "Detection Script complete. $WingetDetectionScriptDestination" + } + else { + Write-Log 'The # Settings section was not found in the script.' -ForegroundColor 'Red' + } + + + #Build RequirementScript + if ($Row.UpdateOnly -eq $True) { + $WingetRequirementScriptSource = "$currentDirectory\Winget-WrapperRequirements.ps1" + $WingetRequirementScriptDestination = "$PackageFolderPath\WinGet-WrapperRequirements-$($Row.PackageID).ps1" - # Copy the source script to the destination - Copy-Item -Path $WingetRequirementScriptSource -Destination $WingetRequirementScriptDestination + # Copy the source script to the destination + Copy-Item -Path $WingetRequirementScriptSource -Destination $WingetRequirementScriptDestination - # Read the destination script - $scriptContent = Get-Content -Path $WingetRequirementScriptDestination + # Read the destination script + $scriptContent = Get-Content -Path $WingetRequirementScriptDestination - # Check if "Exact WinGet Package ID" is present in the script content - if ($scriptContent -match "Exact WinGet Package ID") { - # Replace "Exact WinGet Package ID" with the actual value of $PackageID - $scriptContent = $scriptContent -replace "Exact WinGet Package ID", $Row.PackageID + # Check if "Exact WinGet Package ID" is present in the script content + if ($scriptContent -match 'Exact WinGet Package ID') { + # Replace "Exact WinGet Package ID" with the actual value of $PackageID + $scriptContent = $scriptContent -replace 'Exact WinGet Package ID', $Row.PackageID - # Save the updated script content - Set-Content -Path $WingetRequirementScriptDestination -Value $scriptContent + # Save the updated script content + Set-Content -Path $WingetRequirementScriptDestination -Value $scriptContent - Write-Log "Requirement Script complete. $WingetRequirementScriptDestination" - } else { - Write-Log "The text 'Exact WinGet Package ID' was not found in the script." -ForegroundColor "Red" - } - } - -#Build Targetversion to use with intune package -if ($row.TargetVersion -ne $null -and $row.TargetVersion -ne "") { - $VersionInfo = $row.TargetVersion - } -else { - $VersionInfo = "Latest" -} - -#Convert Context -if ($row.Context -in @("Machine", "machine")) { - $ContextConverted = "System" -} -elseif ($row.Context -in @("User", "user")) { - $ContextConverted = "User" -} - -#Build IntuneWin Folder (including pre/postscripts if specified in CSV) -# Create a folder named "InTuneWin" if it doesn't exist -try { -$intuneWinFolderPath = Join-Path -Path $PackageFolderPath -ChildPath "InTuneWin" -if (-not (Test-Path -Path $intuneWinFolderPath -PathType Container)) { - New-Item -Path $intuneWinFolderPath -ItemType Directory | Out-Null -} -# Copy WinGet-Wrapper.ps1 -Copy-Item -Path "$currentDirectory\WinGet-Wrapper.ps1" -Destination $intuneWinFolderPath -ErrorAction Stop - -# Copy pre or post script if specified -if ($row.PreScriptInstall -ne $null -and $row.PreScriptInstall -ne "") { - Copy-Item -Path $row.PreScriptInstall -Destination $intuneWinFolderPath -ErrorAction Stop - Write-Log "Copied $($row.PreScriptInstall) to $($intuneWinFolderPath)" -} -if ($row.PostScriptInstall -ne $null -and $row.PostScriptInstall -ne "") { - Copy-Item -Path $row.PostScriptInstall -Destination $intuneWinFolderPath -ErrorAction Stop - Write-Log "Copied $($row.PostScriptInstall) to $($intuneWinFolderPath)" -} -if ($row.PreScriptUninstall -ne $null -and $row.PreScriptUninstall -ne "") { - Copy-Item -Path $row.PreScriptUninstall -Destination $intuneWinFolderPath -ErrorAction Stop - Write-Log "Copied $($row.PreScriptUninstall) to $($intuneWinFolderPath)" -} -if ($row.PostScriptUninstall -ne $null -and $row.PostScriptUninstall -ne "") { - Copy-Item -Path $row.PostScriptUninstall -Destination $intuneWinFolderPath -ErrorAction Stop - Write-Log "Copied $($row.PostScriptUninstall) to $($intuneWinFolderPath)" -}} -catch { - Write-Log "Failed to copy files to build InTuneWin package. Please check pre/post script is found" - return -} - -# Build WinGet-Wrapper.intunewin -Write-Log "Building WinGet-Wrapper.InTuneWin file" -try { -[string]$toolargs = "-c ""$($intuneWinFolderPath)"" -s ""WinGet-Wrapper.ps1"" -o ""$($PackageFolderPath)"" -q" + Write-Log "Requirement Script complete. $WingetRequirementScriptDestination" + } + else { + Write-Log "The text 'Exact WinGet Package ID' was not found in the script." -ForegroundColor 'Red' + } + } + + #Build Targetversion to use with intune package + if ($row.TargetVersion -ne $null -and $row.TargetVersion -ne '') { + $VersionInfo = $row.TargetVersion + } + else { + $VersionInfo = 'Latest' + } + + #Convert Context + if ($row.Context -in @('Machine', 'machine')) { + $ContextConverted = 'System' + } + elseif ($row.Context -in @('User', 'user')) { + $ContextConverted = 'User' + } + + #Build IntuneWin Folder (including pre/postscripts if specified in CSV) + # Create a folder named "InTuneWin" if it doesn't exist + try { + $intuneWinFolderPath = Join-Path -Path $PackageFolderPath -ChildPath 'InTuneWin' + if (-not (Test-Path -Path $intuneWinFolderPath -PathType Container)) { + New-Item -Path $intuneWinFolderPath -ItemType Directory | Out-Null + } + # Copy WinGet-Wrapper.ps1 + Copy-Item -Path "$currentDirectory\WinGet-Wrapper.ps1" -Destination $intuneWinFolderPath -ErrorAction Stop + + # Copy pre or post script if specified + if ($row.PreScriptInstall -ne $null -and $row.PreScriptInstall -ne '') { + Copy-Item -Path $row.PreScriptInstall -Destination $intuneWinFolderPath -ErrorAction Stop + Write-Log "Copied $($row.PreScriptInstall) to $($intuneWinFolderPath)" + } + if ($row.PostScriptInstall -ne $null -and $row.PostScriptInstall -ne '') { + Copy-Item -Path $row.PostScriptInstall -Destination $intuneWinFolderPath -ErrorAction Stop + Write-Log "Copied $($row.PostScriptInstall) to $($intuneWinFolderPath)" + } + if ($row.PreScriptUninstall -ne $null -and $row.PreScriptUninstall -ne '') { + Copy-Item -Path $row.PreScriptUninstall -Destination $intuneWinFolderPath -ErrorAction Stop + Write-Log "Copied $($row.PreScriptUninstall) to $($intuneWinFolderPath)" + } + if ($row.PostScriptUninstall -ne $null -and $row.PostScriptUninstall -ne '') { + Copy-Item -Path $row.PostScriptUninstall -Destination $intuneWinFolderPath -ErrorAction Stop + Write-Log "Copied $($row.PostScriptUninstall) to $($intuneWinFolderPath)" + } + } + catch { + Write-Log 'Failed to copy files to build InTuneWin package. Please check pre/post script is found' + return + } + + # Build WinGet-Wrapper.intunewin + Write-Log 'Building WinGet-Wrapper.InTuneWin file' + try { + [string]$toolargs = "-c ""$($intuneWinFolderPath)"" -s ""WinGet-Wrapper.ps1"" -o ""$($PackageFolderPath)"" -q" (Start-Process -FilePath "$currentDirectory\IntuneWinAppUtil.exe" -ArgumentList $toolargs -PassThru:$true -ErrorAction Stop -NoNewWindow).WaitForExit() - # Check that IntuneWin was created - if (Test-Path -Path "$PackageFolderPath\WinGet-Wrapper.intunewin" -PathType Leaf) { - Write-Log "IntuneWinAppUtil.exe built WinGet-Wrapper.intunewin for $PackageName" - } - else { - Write-Log "IntuneWinAppUtil.exe could not build WinGet-Wrapper.intunewin" - return - } + # Check that IntuneWin was created + if (Test-Path -Path "$PackageFolderPath\WinGet-Wrapper.intunewin" -PathType Leaf) { + Write-Log "IntuneWinAppUtil.exe built WinGet-Wrapper.intunewin for $PackageName" + } + else { + Write-Log 'IntuneWinAppUtil.exe could not build WinGet-Wrapper.intunewin' + return + } -} -catch { - Write-Log "Error running IntuneWinAppUtil.exe" - return -} - -#Set WinGet-Wrapper.intunewin path -$WinGetWrapperInTuneWinFilePath = Join-Path -Path $PackageFolderPath -ChildPath 'WinGet-Wrapper.intunewin' - -#Detection -$DetectionRuleScript = New-IntuneWin32AppDetectionRuleScript -ScriptFile $WingetDetectionScriptDestination - -#RequirementRule Base -$RequirementRule = New-IntuneWin32AppRequirementRule -Architecture "All" -MinimumSupportedWindowsRelease "W10_20H2" - -# Build base Add-InTuneWin32App Arguments -$AddInTuneWin32AppArguments = @{ - FilePath = "$WinGetWrapperInTuneWinFilePath" - DisplayName = "$PackageName" - Description = "$Description" - Publisher = "$Publisher" - AppVersion = "$VersionInfo" - Developer = "$Author" - InstallCommandLine = "$InstallCommandLine" - UninstallCommandLine = "$UninstallCommandLine" - InstallExperience = "$ContextConverted" - RestartBehavior = "suppress" - Owner = "$currentUser" - Notes = "Created by $currentUser at $Timestamp using WinGet-WrapperCreateFromCSV (https://github.com/SorenLundt/WinGet-Wrapper)" - DetectionRule = $DetectionRuleScript - RequirementRule = $RequirementRule -} - -# Build AdditionalRequirementRule (if UpdateOnly True) -if ($Row.UpdateOnly -eq $True) { - $AdditionalRequirementRule = New-IntuneWin32AppRequirementRuleScript -ScriptFile $WingetRequirementScriptDestination -ScriptContext "$ContextConverted" -StringComparisonOperator "equal" -StringOutputDataType -StringValue "Installed" - $AddInTuneWin32AppArguments.AdditionalRequirementRule = $AdditionalRequirementRule -} else { -} - -# If overwrite enabled , remove win32app from intune before importing -# Disabled section. Needs more work. -<# + } + catch { + Write-Log 'Error running IntuneWinAppUtil.exe' + return + } + + #Set WinGet-Wrapper.intunewin path + $WinGetWrapperInTuneWinFilePath = Join-Path -Path $PackageFolderPath -ChildPath 'WinGet-Wrapper.intunewin' + + #Detection + $DetectionRuleScript = New-IntuneWin32AppDetectionRuleScript -ScriptFile $WingetDetectionScriptDestination + + #RequirementRule Base + $RequirementRule = New-IntuneWin32AppRequirementRule -Architecture 'All' -MinimumSupportedWindowsRelease 'W10_20H2' + + # Build base Add-InTuneWin32App Arguments + $AddInTuneWin32AppArguments = @{ + FilePath = "$WinGetWrapperInTuneWinFilePath" + DisplayName = "$PackageName" + Description = "$Description" + Publisher = "$Publisher" + AppVersion = "$VersionInfo" + Developer = "$Author" + InstallCommandLine = "$InstallCommandLine" + UninstallCommandLine = "$UninstallCommandLine" + InstallExperience = "$ContextConverted" + RestartBehavior = 'suppress' + Owner = "$currentUser" + Notes = "Created by $currentUser at $Timestamp using WinGet-WrapperCreateFromCSV (https://github.com/SorenLundt/WinGet-Wrapper)" + DetectionRule = $DetectionRuleScript + RequirementRule = $RequirementRule + } + + # Build AdditionalRequirementRule (if UpdateOnly True) + if ($Row.UpdateOnly -eq $True) { + $AdditionalRequirementRule = New-IntuneWin32AppRequirementRuleScript -ScriptFile $WingetRequirementScriptDestination -ScriptContext "$ContextConverted" -StringComparisonOperator 'equal' -StringOutputDataType -StringValue 'Installed' + $AddInTuneWin32AppArguments.AdditionalRequirementRule = $AdditionalRequirementRule + } + else { + } + + # If overwrite enabled , remove win32app from intune before importing + # Disabled section. Needs more work. + <# if ($Overwrite -eq $True) { try{ Write-Log "Overwrite enabled - Attempting to remove Win32App if it already exists in InTune - $PackageName " @@ -775,8 +786,8 @@ if ($Overwrite -eq $True) { } #> -# Disabled section. Needs more work. -<# + # Disabled section. Needs more work. + <# Write-Log "Checking if application already exists in Intune - $PackageName" # Get the Intune Win32 apps with the specified display name $CheckIntuneAppExists = Get-IntuneWin32App -DisplayName "$PackageName" -WarningAction SilentlyContinue @@ -796,85 +807,109 @@ Write-Log "Checking if application already exists in Intune - $PackageName" } #> -#Import application to InTune -try { - Write-Log "Importing application '$PackageName' to InTune" - $AppImport = Add-IntuneWin32App @AddInTuneWin32AppArguments -WarningAction Continue -ErrorAction Continue - $AppID = $AppImport.ID - $row | Add-Member -MemberType NoteProperty -Name "AppID" -Value $AppID #Write AppID to $row - Write-Log "Imported application '$PackageName' to InTune" -ForeGroundColor "Green" - $imported = $True -} -catch { - Write-Log "An error occurred: $($_.Exception.Message)" -ForeGroundColor "Red" - $imported = $False - $row | Add-Member -MemberType NoteProperty -Name "Imported" -Value $imported #Write imported status to $row - $errortext = "Error Importing: $($_.Exception.Message)" - $row | Add-Member -MemberType NoteProperty -Name "ErrorText" -Value $errortext #Write errortext to $row - continue -} - -# Deploy Application if set - Install Intent "Required" -try { - if ($Row.InstallIntent -contains "Required" -and ($null -ne $Row.GroupID -and $Row.GroupID -ne "")) { - Add-IntuneWin32AppAssignmentGroup -Include -ID $Row.AppID -GroupID $Row.GroupID -Intent $row.InstallIntent -Notification $row.Notification -ErrorAction continue - Write-Log "Deployed AppID:$($Row.AppID) to $($Row.GroupID)" -ForeGroundColor "Green" - } + #Import application to InTune + try { + Write-Log "Importing application '$PackageName' to InTune" + $AppImport = Add-IntuneWin32App @AddInTuneWin32AppArguments -WarningAction Stop + $AppID = $AppImport.ID + $row | Add-Member -MemberType NoteProperty -Name 'AppID' -Value $AppID #Write AppID to $row + Write-Log "Imported application '$PackageName' to InTune" -ForeGroundColor 'Green' + $imported = $True + } + catch { + # Check if permission is missing and fix it + if ($($_.Exception.Message) -match "DeviceManagementApps.ReadWrite.All") { + Connect-MgGraph -ClientId $ClientID -Scope 'DeviceManagementApps.ReadWrite.All' -TenantId $TenantID -ErrorAction Stop + Start-Sleep -Seconds 10 + # Try again to upload after permission grant + try { + Write-Log "Importing application '$PackageName' to InTune" + $AppImport = Add-IntuneWin32App @AddInTuneWin32AppArguments -WarningAction Stop + $AppID = $AppImport.ID + $row | Add-Member -MemberType NoteProperty -Name 'AppID' -Value $AppID #Write AppID to $row + Write-Log "Imported application '$PackageName' to InTune" -ForeGroundColor 'Green' + $imported = $True + } + catch { + Write-Log "An error occurred: $($_.Exception.Message)" -ForeGroundColor 'Red' + $imported = $False + $row | Add-Member -MemberType NoteProperty -Name 'Imported' -Value $imported #Write imported status to $row + $errortext = "Error Importing: $($_.Exception.Message)" + $row | Add-Member -MemberType NoteProperty -Name 'ErrorText' -Value $errortext #Write errortext to $row + continue + } + } + else { + Write-Log "An error occurred: $($_.Exception.Message)" -ForeGroundColor 'Red' + $imported = $False + $row | Add-Member -MemberType NoteProperty -Name 'Imported' -Value $imported #Write imported status to $row + $errortext = "Error Importing: $($_.Exception.Message)" + $row | Add-Member -MemberType NoteProperty -Name 'ErrorText' -Value $errortext #Write errortext to $row + continue + } + + } + + # Deploy Application if set - Install Intent "Required" + try { + if ($Row.InstallIntent -contains 'Required' -and ($null -ne $Row.GroupID -and $Row.GroupID -ne '')) { + Add-IntuneWin32AppAssignmentGroup -Include -ID $Row.AppID -GroupID $Row.GroupID -Intent $row.InstallIntent -Notification $row.Notification -ErrorAction continue + Write-Log "Deployed AppID:$($Row.AppID) to $($Row.GroupID)" -ForeGroundColor 'Green' + } - # Deploy Application if set - Install Intent "Available" - if ($Row.InstallIntent -contains "Available" -and ($null -ne $Row.GroupID -and $Row.GroupID -ne "")) { - Add-IntuneWin32AppAssignmentGroup -Include -ID $Row.AppID -GroupID $Row.GroupID -Intent $row.InstallIntent -Notification $row.Notification -ErrorAction continue - Write-Log "Deployed AppID:$($Row.AppID) to $($Row.GroupID)" -ForeGroundColor "Green" - } -} - catch { - Write-Log "Error deploying $($Row.PackageID) : $_" -} + # Deploy Application if set - Install Intent "Available" + if ($Row.InstallIntent -contains 'Available' -and ($null -ne $Row.GroupID -and $Row.GroupID -ne '')) { + Add-IntuneWin32AppAssignmentGroup -Include -ID $Row.AppID -GroupID $Row.GroupID -Intent $row.InstallIntent -Notification $row.Notification -ErrorAction continue + Write-Log "Deployed AppID:$($Row.AppID) to $($Row.GroupID)" -ForeGroundColor 'Green' + } + } + catch { + Write-Log "Error deploying $($Row.PackageID) : $_" + } + + #Success + $imported = $True + $row | Add-Member -MemberType NoteProperty -Name 'Imported' -Value $imported #Write imported status to $row -#Success -$imported = $True -$row | Add-Member -MemberType NoteProperty -Name "Imported" -Value $imported #Write imported status to $row + } + catch { + #Failed + $imported = $False + $row | Add-Member -MemberType NoteProperty -Name 'Imported' -Value $imported #Write imported status to $row + $errortext = "Unknown Error: $_.Exception.Message" + $row | Add-Member -MemberType NoteProperty -Name 'ErrorText' -Value $errortext #Write errortext to $row - } - catch { - #Failed - $imported = $False - $row | Add-Member -MemberType NoteProperty -Name "Imported" -Value $imported #Write imported status to $row - $errortext = "Unknown Error: $_.Exception.Message" - $row | Add-Member -MemberType NoteProperty -Name "ErrorText" -Value $errortext #Write errortext to $row + } - } + #If more packages to import, wait 15 seconds to avoid throttling. Microsoft Graph throttling ? + # Check if there are more than 2 rows in $data + if ($data.Count -gt 2) { + Write-Log 'Waiting 15s before importing next package.. (Throttle)' + Start-Sleep -Seconds 15 + } -#If more packages to import, wait 15 seconds to avoid throttling. Microsoft Graph throttling ? - # Check if there are more than 2 rows in $data - if ($data.Count -gt 2) { - Write-Log "Waiting 15s before importing next package.. (Throttle)" - Start-Sleep -Seconds 15 } - -} } ###### END FOREACH ###### #Write Results -Write-Log "---- RESULTS Package Creation ----" +Write-Log '---- RESULTS Package Creation ----' foreach ($row in $data) { $importedStatus = $row.Imported - $textColor = "Green" # Default to green - $importedtext = "Success" #Default to success + $textColor = 'Green' # Default to green + $importedtext = 'Success' #Default to success if (-not $importedStatus) { - $textColor = "Red" # Change to red if Imported is False - $importedtext = "Failed" + $textColor = 'Red' # Change to red if Imported is False + $importedtext = 'Failed' } - Write-Log "" + Write-Log '' $formattedText = "IMPORTED:$ImportedText PackageID:$($row.PackageID) AppID:$($row.AppID) TargetVersion:$($row.TargetVersion) Context:$($row.Context) UpdateOnly: $($row.UpdateOnly) AcceptNewerVersion: $($row.AcceptNewerVersion) ErrorText: $($row.ErrorText)" Write-Log $formattedText -ForegroundColor $textColor # If deployed also show these results - if ($null = $row.GroupID -or $row.GroupID -ne ""){ - if ($importedStatus -eq $True) - { - Write-Log "> DEPLOYED:$($row.PackageID) AppID:$($row.AppID) ----> GroupID:$($row.GroupID) InstallIntent:$($row.InstallIntent) Notification:$($row.Notification)" -ForegroundColor $textColor + if ($null = $row.GroupID -or $row.GroupID -ne '') { + if ($importedStatus -eq $True) { + Write-Log "> DEPLOYED:$($row.PackageID) AppID:$($row.AppID) ----> GroupID:$($row.GroupID) InstallIntent:$($row.InstallIntent) Notification:$($row.Notification)" -ForegroundColor $textColor } } Write-Host "Log File: $LogFile" diff --git a/WinGet-WrapperImportGUI.ps1 b/WinGet-WrapperImportGUI.ps1 index 9e80549..f6a7c81 100644 --- a/WinGet-WrapperImportGUI.ps1 +++ b/WinGet-WrapperImportGUI.ps1 @@ -20,21 +20,21 @@ Param ( ) # Greeting -write-host "" -Write-Host "****************************************************" -Write-Host " WinGet-Wrapper)" -Write-Host " https://github.com/SorenLundt/WinGet-Wrapper" -Write-Host "" -Write-Host " GNU General Public License v3" -Write-Host "****************************************************" -write-host " WinGet-WrapperImportGUI Starting up.." -write-host "" +Write-Host '' +Write-Host '****************************************************' +Write-Host ' WinGet-Wrapper)' +Write-Host ' https://github.com/SorenLundt/WinGet-Wrapper' +Write-Host '' +Write-Host ' GNU General Public License v3' +Write-Host '****************************************************' +Write-Host ' WinGet-WrapperImportGUI Starting up..' +Write-Host '' # Function to show loading progress bar in console. function Show-ConsoleProgress { param ( - [string]$Activity = "Loading Winget-Wrapper Import GUI", - [string]$Status = "", + [string]$Activity = 'Loading Winget-Wrapper Import GUI', + [string]$Status = '', [int]$PercentComplete = 0 ) Write-Host "$Status - [$PercentComplete%]" @@ -42,90 +42,116 @@ function Show-ConsoleProgress { } # Update ConsoleProgress -Show-ConsoleProgress -PercentComplete 0 -Status "Initializing..." +Show-ConsoleProgress -PercentComplete 0 -Status 'Initializing...' # Add required assemblies Add-Type -AssemblyName System.Windows.Forms Add-Type -AssemblyName System.Drawing # Set the timestamp for log file -$timestamp = Get-Date -Format "yyyyMMddHHmmss" +$timestamp = Get-Date -Format 'yyyyMMddHHmmss' #Find Script root path if (-not $PSScriptRoot) { $scriptRoot = (Get-Location -PSProvider FileSystem).ProviderPath -} else { +} +else { $scriptRoot = $PSScriptRoot } # Create logs folder if it doesn't exist -$LogFolder = Join-Path -Path $scriptRoot -ChildPath "Logs" - # Create logs folder if it doesn't exist - if (-not (Test-Path -Path $LogFolder)) { - New-Item -Path $LogFolder -ItemType Directory | Out-Null - } +$LogFolder = Join-Path -Path $scriptRoot -ChildPath 'Logs' +# Create logs folder if it doesn't exist +if (-not (Test-Path -Path $LogFolder)) { + New-Item -Path $LogFolder -ItemType Directory | Out-Null +} # Install and load required modules -$intuneWin32AppModule = "IntuneWin32App" -$microsoftGraphIntuneModule = "Microsoft.Graph.Intune" +$intuneWin32AppModule = 'IntuneWin32App' +$microsoftGraphIntuneModule = 'Microsoft.Graph.Intune' +$microsoftGraphAuthenticationModule = 'Microsoft.Graph.Authentication' #DEBUG (Skip ModuleCheck) #$SKIPMODULECHECK = $true if (-not $SKIPMODULECHECK) { -# Check IntuneWin32App module -# Update ConsoleProgress -Show-ConsoleProgress -PercentComplete 10 -Status "Checking and updating $intuneWin32AppModule.." -$moduleInstalled = Get-InstalledModule -Name $intuneWin32AppModule -ErrorAction SilentlyContinue -if (-not $moduleInstalled) { - Install-Module -Name $intuneWin32AppModule -Force -} else { - $latestVersion = (Find-Module -Name $intuneWin32AppModule).Version - if ($moduleInstalled.Version -lt $latestVersion) { - Update-Module -Name $intuneWin32AppModule -Force - } else { - Write-Host "Module $intuneWin32AppModule is already up-to-date." -ForegroundColor Green + # Check IntuneWin32App module + # Update ConsoleProgress + Show-ConsoleProgress -PercentComplete 10 -Status "Checking and updating $intuneWin32AppModule.." + $moduleInstalled = Get-InstalledModule -Name $intuneWin32AppModule -ErrorAction SilentlyContinue + if (-not $moduleInstalled) { + Install-Module -Name $intuneWin32AppModule -Force } -} + else { + $latestVersion = (Find-Module -Name $intuneWin32AppModule).Version + if ($moduleInstalled.Version -lt $latestVersion) { + Update-Module -Name $intuneWin32AppModule -Force + } + else { + Write-Host "Module $intuneWin32AppModule is already up-to-date." -ForegroundColor Green + } + } + # Check Microsoft.Graph.Intune module + # Update ConsoleProgress + Show-ConsoleProgress -PercentComplete 40 -Status "Checking and updating $microsoftGraphIntuneModule.." + $moduleInstalled = Get-InstalledModule -Name $microsoftGraphIntuneModule -ErrorAction SilentlyContinue -# Check Microsoft.Graph.Intune module -# Update ConsoleProgress -Show-ConsoleProgress -PercentComplete 40 -Status "Checking and updating $microsoftGraphIntuneModule.." -$moduleInstalled = Get-InstalledModule -Name $microsoftGraphIntuneModule -ErrorAction SilentlyContinue - -if (-not $moduleInstalled) { - Install-Module -Name $microsoftGraphIntuneModule -Force -} else { - $latestVersion = (Find-Module -Name $microsoftGraphIntuneModule).Version - if ($moduleInstalled.Version -lt $latestVersion) { - Update-Module -Name $microsoftGraphIntuneModule -Force - } else { - Write-Host "Module $microsoftGraphIntuneModule is already up-to-date." -ForegroundColor Green + if (-not $moduleInstalled) { + Install-Module -Name $microsoftGraphIntuneModule -Force + } + else { + $latestVersion = (Find-Module -Name $microsoftGraphIntuneModule).Version + if ($moduleInstalled.Version -lt $latestVersion) { + Update-Module -Name $microsoftGraphIntuneModule -Force + } + else { + Write-Host "Module $microsoftGraphIntuneModule is already up-to-date." -ForegroundColor Green + } + } + + + # Check Microsoft.Graph.Authentication module + # Update ConsoleProgress + Show-ConsoleProgress -PercentComplete 40 -Status "Checking and updating $microsoftGraphAuthenticationModule.." + $moduleInstalled = Get-InstalledModule -Name $microsoftGraphAuthenticationModule -ErrorAction SilentlyContinue + + if (-not $moduleInstalled) { + Install-Module -Name $microsoftGraphAuthenticationModule -Force + } + else { + $latestVersion = (Find-Module -Name $microsoftGraphAuthenticationModule).Version + if ($moduleInstalled.Version -lt $latestVersion) { + Update-Module -Name $microsoftGraphAuthenticationModule -Force + } + else { + Write-Host "Module $microsoftGraphAuthenticationModule is already up-to-date." -ForegroundColor Green + + } } -} } #Import modules -Show-ConsoleProgress -PercentComplete 60 -Status "Importing module $intuneWin32AppModule.." -Import-Module -Name "IntuneWin32App" +Show-ConsoleProgress -PercentComplete 60 -Status "Importing module $intuneWin32AppModule.." +Import-Module -Name 'IntuneWin32App' -Show-ConsoleProgress -PercentComplete 80 -Status "Importing module $microsoftGraphIntuneModule.." -Import-Module -Name "Microsoft.Graph.Intune" +Show-ConsoleProgress -PercentComplete 80 -Status "Importing module $microsoftGraphIntuneModule.." +Import-Module -Name 'Microsoft.Graph.Intune' -Show-ConsoleProgress -PercentComplete 90 -Status "Unblocking script files (Unblock-File)" +Show-ConsoleProgress -PercentComplete 90 -Status 'Unblocking script files (Unblock-File)' # Unblock all files in the current directory $files = Get-ChildItem -Path . -File foreach ($file in $files) { try { Unblock-File -Path $file.FullName - } catch { + } + catch { Write-Host "Failed to unblock: $($file.FullName) - $_" } } # Update ConsoleProgress -Show-ConsoleProgress -PercentComplete 80 -Status "Loading functions.." +Show-ConsoleProgress -PercentComplete 80 -Status 'Loading functions..' #Functions function Write-ConsoleTextBox { @@ -135,7 +161,7 @@ function Write-ConsoleTextBox { ) if (-not $NoTimeStamp) { - $TimeStamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" + $TimeStamp = Get-Date -Format 'yyyy-MM-dd HH:mm:ss' $Message = "[$TimeStamp] $Message" } @@ -162,12 +188,12 @@ function Update-GUIFromLogFile { } # Update ConsoleProgress -Show-ConsoleProgress -PercentComplete 90 -Status "Loading GUI elements.." +Show-ConsoleProgress -PercentComplete 90 -Status 'Loading GUI elements..' # GUI # Create form $form = New-Object System.Windows.Forms.Form -$form.Text = "Winget-Wrapper Import GUI - https://github.com/SorenLundt/WinGet-Wrapper" +$form.Text = 'Winget-Wrapper Import GUI - https://github.com/SorenLundt/WinGet-Wrapper' $form.Width = 1475 $form.Height = 980 $form.BackColor = [System.Drawing.Color]::WhiteSmoke @@ -176,12 +202,13 @@ $form.Topmost = $false $form.MaximizeBox = $False # Set the icon for the form -write-host "$scriptRoot" -$iconPath = Join-Path -Path $scriptRoot -ChildPath "Winget-Wrapper.ico" +Write-Host "$scriptRoot" +$iconPath = Join-Path -Path $scriptRoot -ChildPath 'Winget-Wrapper.ico' if (Test-Path $iconPath) { $icon = New-Object System.Drawing.Icon($iconPath) $form.Icon = $icon -} else { +} +else { Write-Host "Icon file not found at $iconPath" } @@ -219,13 +246,13 @@ $form.Controls.Add($ColumnHelpLabel) # Add click event to the LinkLabel $linkLabelGitHub.Add_LinkClicked({ - Start-Process "https://github.com/SorenLundt/WinGet-Wrapper" # Change to your desired URL -}) + Start-Process 'https://github.com/SorenLundt/WinGet-Wrapper' # Change to your desired URL + }) # Click event for Column Help Button $ColumnHelpLabel.Add_Click({ - GetColumnDefinitions -}) + GetColumnDefinitions + }) # Create TextBox for search string $searchBox = New-Object System.Windows.Forms.TextBox @@ -239,7 +266,7 @@ $searchBoxtooltip.SetToolTip($searchBox, 'Enter software name, ex. VLC, 7-zip, e $searchButton = New-Object System.Windows.Forms.Button $searchButton.Location = New-Object System.Drawing.Point(420, 8) $searchButton.Width = 50 -$searchButton.Text = "Search" +$searchButton.Text = 'Search' $form.Controls.Add($searchButton) # Create Label to display search error @@ -253,7 +280,7 @@ $form.Controls.Add($searchErrorLabel) $resultsLabel = New-Object System.Windows.Forms.Label $resultsLabel.Location = New-Object System.Drawing.Point(10, 37) $resultsLabel.Width = 200 -$resultsLabel.Text = "WinGet Packages" +$resultsLabel.Text = 'WinGet Packages' $form.Controls.Add($resultsLabel) # Create DataGridView for results @@ -265,9 +292,9 @@ $dataGridView.SelectionMode = [System.Windows.Forms.DataGridViewSelectionMode]:: $form.Controls.Add($dataGridView) # Add columns to DataGridView -$dataGridView.Columns.Add("Name", "Name") -$dataGridView.Columns.Add("ID", "ID") -$dataGridView.Columns.Add("Version", "Version") +$dataGridView.Columns.Add('Name', 'Name') +$dataGridView.Columns.Add('ID', 'ID') +$dataGridView.Columns.Add('Version', 'Version') # Set initial widths for columns in the DataGridView $dataGridView.Columns['Name'].Width = 200 # Adjust the width as needed @@ -278,7 +305,7 @@ $dataGridView.Columns['Version'].Width = 100 # Adjust the width as needed $resultsLabel = New-Object System.Windows.Forms.Label $resultsLabel.Location = New-Object System.Drawing.Point(650, 37) $resultsLabel.Width = 200 -$resultsLabel.Text = "InTune Import List" +$resultsLabel.Text = 'InTune Import List' $form.Controls.Add($resultsLabel) # Create a second DataGridView @@ -289,33 +316,33 @@ $dataGridViewSelected.Height = 500 $form.Controls.Add($dataGridViewSelected) # Add columns to the second DataGridView -$dataGridViewSelected.Columns.Add("PackageID", "PackageID") -$dataGridViewSelected.Columns.Add("Context", "Context") -$dataGridViewSelected.Columns.Add("AcceptNewerVersion", "AcceptNewerVersion") -$dataGridViewSelected.Columns.Add("UpdateOnly", "UpdateOnly") -$dataGridViewSelected.Columns.Add("TargetVersion", "TargetVersion") -$dataGridViewSelected.Columns.Add("StopProcessInstall", "StopProcessInstall") -$dataGridViewSelected.Columns.Add("StopProcessUninstall", "StopProcessUninstall") -$dataGridViewSelected.Columns.Add("PreScriptInstall", "PreScriptInstall") -$dataGridViewSelected.Columns.Add("PostScriptInstall", "PostScriptInstall") -$dataGridViewSelected.Columns.Add("PreScriptUninstall", "PreScriptUninstall") -$dataGridViewSelected.Columns.Add("PostScriptUninstall", "PostScriptUninstall") -$dataGridViewSelected.Columns.Add("CustomArgumentListInstall", "CustomArgumentListInstall") -$dataGridViewSelected.Columns.Add("CustomArgumentListUninstall", "CustomArgumentListUninstall") -$dataGridViewSelected.Columns.Add("InstallIntent", "InstallIntent") -$dataGridViewSelected.Columns.Add("Notification", "Notification") -$dataGridViewSelected.Columns.Add("GroupID", "GroupID") +$dataGridViewSelected.Columns.Add('PackageID', 'PackageID') +$dataGridViewSelected.Columns.Add('Context', 'Context') +$dataGridViewSelected.Columns.Add('AcceptNewerVersion', 'AcceptNewerVersion') +$dataGridViewSelected.Columns.Add('UpdateOnly', 'UpdateOnly') +$dataGridViewSelected.Columns.Add('TargetVersion', 'TargetVersion') +$dataGridViewSelected.Columns.Add('StopProcessInstall', 'StopProcessInstall') +$dataGridViewSelected.Columns.Add('StopProcessUninstall', 'StopProcessUninstall') +$dataGridViewSelected.Columns.Add('PreScriptInstall', 'PreScriptInstall') +$dataGridViewSelected.Columns.Add('PostScriptInstall', 'PostScriptInstall') +$dataGridViewSelected.Columns.Add('PreScriptUninstall', 'PreScriptUninstall') +$dataGridViewSelected.Columns.Add('PostScriptUninstall', 'PostScriptUninstall') +$dataGridViewSelected.Columns.Add('CustomArgumentListInstall', 'CustomArgumentListInstall') +$dataGridViewSelected.Columns.Add('CustomArgumentListUninstall', 'CustomArgumentListUninstall') +$dataGridViewSelected.Columns.Add('InstallIntent', 'InstallIntent') +$dataGridViewSelected.Columns.Add('Notification', 'Notification') +$dataGridViewSelected.Columns.Add('GroupID', 'GroupID') # Set initial widths for columns in the DataGridViewSelected -foreach ($column in $dataGridViewSelected.Columns){ - $column.Width = "80" +foreach ($column in $dataGridViewSelected.Columns) { + $column.Width = '80' } # Create Button for exporting CSV from dataGridViewSelected $exportButton = New-Object System.Windows.Forms.Button $exportButton.Location = New-Object System.Drawing.Point(760, 565) $exportButton.Width = 100 -$exportButton.Text = "Export CSV" +$exportButton.Text = 'Export CSV' $form.Controls.Add($exportButton) # Create Button for moving selected rows with a right-arrow icon @@ -333,10 +360,10 @@ $arrowIcon = New-Object System.Drawing.Bitmap 50, 50 $arrowGraphics = [System.Drawing.Graphics]::FromImage($arrowIcon) $arrowBrush = [System.Drawing.Brushes]::Black $arrowGraphics.FillPolygon($arrowBrush, @( - [System.Drawing.Point]::new(10, 10), - [System.Drawing.Point]::new(30, 25), - [System.Drawing.Point]::new(10, 40) -)) + [System.Drawing.Point]::new(10, 10), + [System.Drawing.Point]::new(30, 25), + [System.Drawing.Point]::new(10, 40) + )) $arrowGraphics.Dispose() # Set the button's appearance and icon @@ -344,56 +371,110 @@ $moveButton.FlatStyle = 'Flat' $moveButton.FlatAppearance.BorderSize = 0 $moveButton.BackgroundImage = $arrowIcon $moveButton.BackgroundImageLayout = 'Stretch' -$moveButton.Text = "" +$moveButton.Text = '' $form.Controls.Add($moveButton) # Create Button for deleting selected rows $deleteButton = New-Object System.Windows.Forms.Button $deleteButton.Location = New-Object System.Drawing.Point(1350, 565) $deleteButton.Width = 100 -$deleteButton.Text = "Delete Selected" +$deleteButton.Text = 'Delete Selected' $form.Controls.Add($deleteButton) # Create Button for importing CSV to dataGridViewSelected $importCSVButton = New-Object System.Windows.Forms.Button $importCSVButton.Location = New-Object System.Drawing.Point(650, 565) $importCSVButton.Width = 100 -$importCSVButton.Text = "Import CSV" +$importCSVButton.Text = 'Import CSV' $form.Controls.Add($importCSVButton) # Create a TextBox for console output $consoleTextBox = New-Object System.Windows.Forms.TextBox -$consoleTextBox.Location = New-Object System.Drawing.Point(10, 650) +$consoleTextBox.Location = New-Object System.Drawing.Point(10, 680) $consoleTextBox.Width = 1420 $consoleTextBox.Height = 280 $consoleTextBox.Multiline = $true -$consoleTextBox.ScrollBars = "Vertical" +$consoleTextBox.ScrollBars = 'Vertical' $form.Controls.Add($consoleTextBox) # Create Button for importing data into InTune $InTuneimportButton = New-Object System.Windows.Forms.Button -$InTuneimportButton.Location = New-Object System.Drawing.Point(650, 615) +$InTuneimportButton.Location = New-Object System.Drawing.Point(650, 640) $InTuneimportButton.Width = 120 -$InTuneimportButton.Text = "Import to InTune" +$InTuneimportButton.Text = 'Import to InTune' $IntuneImportButton.Visible = $True $form.Controls.Add($InTuneimportButton) +# Create Label for $tenantId +$tenantIdLabel = New-Object System.Windows.Forms.Label +$tenantIdLabel.Location = New-Object System.Drawing.Point(650, 600) +$tenantIdLabel.Width = 200 +$tenantIdLabel.Height = 15 +$tenantIdLabel.Text = 'Tenant ID' +$form.Controls.Add($tenantIdLabel) + # Create TextBox for Tenant ID $tenantIDTextBox = New-Object System.Windows.Forms.TextBox -$tenantIDTextBox.Location = New-Object System.Drawing.Point(650, 590) -$tenantIDTextBox.Width = 300 +$tenantIDTextBox.Location = New-Object System.Drawing.Point(650, 615) +$tenantIDTextBox.Width = 250 $form.Controls.Add($tenantIDTextBox) # Help text for Tenant ID textbox -$tenantIDTextBoxDefaultText = "Enter Tenant ID (e.g., company.onmicrosoft.com)" +$tenantIDTextBoxDefaultText = 'Enter Tenant ID (e.g., company.onmicrosoft.com)' $tenantIDTextBox.Text = "$tenantIDTextBoxDefaultText" $tenantIDTextBox.ForeColor = [System.Drawing.Color]::Gray +# Create Label for $clientId +$clientIdLabel = New-Object System.Windows.Forms.Label +$clientIdLabel.Location = New-Object System.Drawing.Point(920, 600) +$clientIdLabel.Width = 50 +$clientIdLabel.Height = 15 +$clientIdLabel.Text = 'Client ID' +$form.Controls.Add($clientIdLabel) + +$clientIdDefaultLabel = New-Object System.Windows.Forms.Label +$clientIdDefaultLabel.Location = New-Object System.Drawing.Point(970, 600) +$clientIdDefaultLabel.Width = 230 +$clientIdDefaultLabel.Height = 15 +$clientIdDefaultLabel.Font = New-Object System.Drawing.Font('Arial', 8) +$clientIdDefaultLabel.ForeColor = [System.Drawing.Color]::Gray +$clientIdDefaultLabel.Text = 'Default: Microsoft Graph Command Line Tools' +$form.Controls.Add($clientIdDefaultLabel) + + +# Create TextBox for Client ID +$clientIDTextBox = New-Object System.Windows.Forms.TextBox +$clientIDTextBox.Location = New-Object System.Drawing.Point(920, 615) +$clientIDTextBox.Width = 280 +$form.Controls.Add($clientIDTextBox) + +# Help text for Client textbox +$clientIDTextBox.Text = '14d82eec-204b-4c2f-b7e8-296a70dab67e' +#$clientIDTextBox.ForeColor = [System.Drawing.Color]::Gray + +# Create Label for $redirectURI +$redirectLabel = New-Object System.Windows.Forms.Label +$redirectLabel.Location = New-Object System.Drawing.Point(1210, 600) +$redirectLabel.Width = 190 +$redirectLabel.Height = 15 +$redirectLabel.Text = 'Redirect URI' +$form.Controls.Add($redirectLabel) + +# Create TextBox for Redirect URL +$redirectURLTextBox = New-Object System.Windows.Forms.TextBox +$redirectURLTextBox.Location = New-Object System.Drawing.Point(1210, 615) +$redirectURLTextBox.Width = 200 +$form.Controls.Add($redirectURLTextBox) + +# Help text for Redirect url textbox +$redirectURLTextBox.Text = 'https://login.microsoftonline.com/common/oauth2/nativeclient' +#$redirectURLTextBox.ForeColor = [System.Drawing.Color]::Gray + # Create Button for Getting Package Details $GetPackageDetails = New-Object System.Windows.Forms.Button $GetPackageDetails.Location = New-Object System.Drawing.Point(10, 565) $GetPackageDetails.Width = 240 -$GetPackageDetails.Text = "Get detailed info for selected package(s)" +$GetPackageDetails.Text = 'Get detailed info for selected package(s)' $GetPackageDetails.Visible = $True $form.Controls.Add($GetPackageDetails) @@ -401,187 +482,223 @@ $form.Controls.Add($GetPackageDetails) $GetPackageVersions = New-Object System.Windows.Forms.Button $GetPackageVersions.Location = New-Object System.Drawing.Point(260, 565) $GetPackageVersions.Width = 240 -$GetPackageVersions.Text = "Get available versions for selected package(s)" +$GetPackageVersions.Text = 'Get available versions for selected package(s)' $GetPackageVersions.Visible = $True $form.Controls.Add($GetPackageVersions) # Update ConsoleProgress -Show-ConsoleProgress -PercentComplete 95 -Status "Loading Event handlers.." +Show-ConsoleProgress -PercentComplete 95 -Status 'Loading Event handlers..' # EVENTS # Event handler for when the textbox gains focus (Enter event) $tenantIDTextBox.Add_Enter({ - if ($tenantIDTextBox.Text -eq "$tenantIDTextBoxDefaultText") { - $tenantIDTextBox.Text = "" - $tenantIDTextBox.ForeColor = [System.Drawing.Color]::Black - } -}) + if ($tenantIDTextBox.Text -eq "$tenantIDTextBoxDefaultText") { + $tenantIDTextBox.Text = '' + $tenantIDTextBox.ForeColor = [System.Drawing.Color]::Black + } + }) # Event handler for when the textbox loses focus (Leave event) $tenantIDTextBox.Add_Leave({ - if ([string]::IsNullOrWhiteSpace($tenantIDTextBox.Text)) { - $tenantIDTextBox.Text = "$tenantIDTextBoxDefaultText" - $tenantIDTextBox.ForeColor = [System.Drawing.Color]::Gray - } -}) + if ([string]::IsNullOrWhiteSpace($tenantIDTextBox.Text)) { + $tenantIDTextBox.Text = "$tenantIDTextBoxDefaultText" + $tenantIDTextBox.ForeColor = [System.Drawing.Color]::Gray + } + }) + +# Event handler for when the textbox gains focus (Enter event) +$clientIDTextBox.Add_Enter({ + if ($clientIDTextBox.Text -eq "$clientIDTextBoxDefaultText") { + $clientIDTextBox.Text = '' + $clientIDTextBox.ForeColor = [System.Drawing.Color]::Black + } + }) + +# Event handler for when the textbox loses focus (Leave event) +$clientIDTextBox.Add_Leave({ + if ([string]::IsNullOrWhiteSpace($clientIDTextBox.Text)) { + $clientIDTextBox.Text = "$clientIDTextBoxDefaultText" + $clientIDTextBox.ForeColor = [System.Drawing.Color]::Gray + } + }) + +# Event handler for when the textbox gains focus (Enter event) +$redirectURLTextBox.Add_Enter({ + if ($redirectURLTextBox.Text -eq "$redirectURLTextBoxDefaultText") { + $redirectURLTextBox.Text = '' + $redirectURLTextBox.ForeColor = [System.Drawing.Color]::Black + } + }) + +# Event handler for when the textbox loses focus (Leave event) +$redirectURLTextBox.Add_Leave({ + if ([string]::IsNullOrWhiteSpace($redirectURLTextBox.Text)) { + $redirectURLTextBox.Text = "$redirectURLTextBoxDefaultText" + $redirectURLTextBox.ForeColor = [System.Drawing.Color]::Gray + } + }) # Event handler for deleting selected rows $deleteButton.Add_Click({ - foreach ($row in $dataGridViewSelected.SelectedRows) { - $packageID = $row.Cells['PackageID'].Value - $dataGridViewSelected.Rows.Remove($row) - Write-ConsoleTextBox "Removed '$PackageID' from import list" + foreach ($row in $dataGridViewSelected.SelectedRows) { + $packageID = $row.Cells['PackageID'].Value + $dataGridViewSelected.Rows.Remove($row) + Write-ConsoleTextBox "Removed '$PackageID' from import list" - } + } - # Autosize columns after deleting rows - $dataGridViewSelected.AutoResizeColumns([System.Windows.Forms.DataGridViewAutoSizeColumnMode]::AllCells) -}) + # Autosize columns after deleting rows + $dataGridViewSelected.AutoResizeColumns([System.Windows.Forms.DataGridViewAutoSizeColumnMode]::AllCells) + }) # Event handler for importing CSV $importCSVButton.Add_Click({ - $openFileDialog = New-Object System.Windows.Forms.OpenFileDialog - $openFileDialog.InitialDirectory = (Get-Location).Path - $openFileDialog.Filter = "CSV files (*.csv)|*.csv" + $openFileDialog = New-Object System.Windows.Forms.OpenFileDialog + $openFileDialog.InitialDirectory = (Get-Location).Path + $openFileDialog.Filter = 'CSV files (*.csv)|*.csv' - $result = $openFileDialog.ShowDialog() - if ($result -eq [System.Windows.Forms.DialogResult]::OK) { - $csvFilePath = $openFileDialog.FileName + $result = $openFileDialog.ShowDialog() + if ($result -eq [System.Windows.Forms.DialogResult]::OK) { + $csvFilePath = $openFileDialog.FileName - # Load CSV data into a PowerShell object - $importedData = Import-Csv -Path $csvFilePath + # Load CSV data into a PowerShell object + $importedData = Import-Csv -Path $csvFilePath - # Clear existing rows in $dataGridViewSelected - $dataGridViewSelected.Rows.Clear() + # Clear existing rows in $dataGridViewSelected + $dataGridViewSelected.Rows.Clear() - # Add rows to $dataGridViewSelected from imported data - foreach ($row in $importedData) { - $dataGridViewSelected.Rows.Add( - $row.PackageID, - $row.Context, - $row.AcceptNewerVersion, - $row.UpdateOnly, - $row.TargetVersion, - $row.StopProcessInstall, - $row.StopProcessUninstall, - $row.PreScriptInstall, - $row.PostScriptInstall, - $row.PreScriptUninstall, - $row.PostScriptUninstall, - $row.CustomArgumentListInstall, - $row.CustomArgumentListUninstall, - $row.InstallIntent, - $row.Notification, - $row.GroupID - ) - } - } else { - $dataGridViewSelected.Rows.Clear() - } + # Add rows to $dataGridViewSelected from imported data + foreach ($row in $importedData) { + $dataGridViewSelected.Rows.Add( + $row.PackageID, + $row.Context, + $row.AcceptNewerVersion, + $row.UpdateOnly, + $row.TargetVersion, + $row.StopProcessInstall, + $row.StopProcessUninstall, + $row.PreScriptInstall, + $row.PostScriptInstall, + $row.PreScriptUninstall, + $row.PostScriptUninstall, + $row.CustomArgumentListInstall, + $row.CustomArgumentListUninstall, + $row.InstallIntent, + $row.Notification, + $row.GroupID + ) + } + } + else { + $dataGridViewSelected.Rows.Clear() + } - # Autosize columns in $dataGridViewSelected after import - $dataGridViewSelected.AutoResizeColumns([System.Windows.Forms.DataGridViewAutoSizeColumnMode]::AllCells) -}) + # Autosize columns in $dataGridViewSelected after import + $dataGridViewSelected.AutoResizeColumns([System.Windows.Forms.DataGridViewAutoSizeColumnMode]::AllCells) + }) # Event handler for exporting CSV - $exportButton.Add_Click({ - # Check if DataGridView is not empty - if ($dataGridViewSelected.Rows.Count -gt 0) { - # Create an empty array to store the selected data - $selectedData = @() - - # Iterate through DataGridView rows - foreach ($row in $dataGridViewSelected.Rows) { - $packageID = $row.Cells['PackageID'].Value - $context = $row.Cells['Context'].Value - $acceptNewerVersion = $row.Cells['AcceptNewerVersion'].Value - $updateOnly = $row.Cells['UpdateOnly'].Value - - # Check if all required values are not null or empty - if ($packageID -ne $null -and $packageID -ne '' -and - $context -ne $null -and $context -ne '' -and - $acceptNewerVersion -ne $null -and $acceptNewerVersion -ne '' -and - $updateOnly -ne $null -and $updateOnly -ne '') { - # Create a hashtable representing the row data and add it to the selected data array - $rowData = [ordered]@{ - 'PackageID' = $packageID - 'Context' = $context - 'AcceptNewerVersion' = $acceptNewerVersion - 'UpdateOnly' = $updateOnly - 'TargetVersion' = $row.Cells['TargetVersion'].Value - 'StopProcessInstall' = $row.Cells['StopProcessInstall'].Value - 'StopProcessUninstall' = $row.Cells['StopProcessUninstall'].Value - 'PreScriptInstall' = $row.Cells['PreScriptInstall'].Value - 'PostScriptInstall' = $row.Cells['PostScriptInstall'].Value - 'PreScriptUninstall' = $row.Cells['PreScriptUninstall'].Value - 'PostScriptUninstall' = $row.Cells['PostScriptUninstall'].Value - 'CustomArgumentListInstall' = $row.Cells['CustomArgumentListInstall'].Value - 'CustomArgumentListUninstall' = $row.Cells['CustomArgumentListUninstall'].Value - 'InstallIntent' = $row.Cells['InstallIntent'].Value - 'Notification' = $row.Cells['Notification'].Value - 'GroupID' = $row.Cells['GroupID'].Value +$exportButton.Add_Click({ + # Check if DataGridView is not empty + if ($dataGridViewSelected.Rows.Count -gt 0) { + # Create an empty array to store the selected data + $selectedData = @() + + # Iterate through DataGridView rows + foreach ($row in $dataGridViewSelected.Rows) { + $packageID = $row.Cells['PackageID'].Value + $context = $row.Cells['Context'].Value + $acceptNewerVersion = $row.Cells['AcceptNewerVersion'].Value + $updateOnly = $row.Cells['UpdateOnly'].Value + + # Check if all required values are not null or empty + if ($packageID -ne $null -and $packageID -ne '' -and + $context -ne $null -and $context -ne '' -and + $acceptNewerVersion -ne $null -and $acceptNewerVersion -ne '' -and + $updateOnly -ne $null -and $updateOnly -ne '') { + # Create a hashtable representing the row data and add it to the selected data array + $rowData = [ordered]@{ + 'PackageID' = $packageID + 'Context' = $context + 'AcceptNewerVersion' = $acceptNewerVersion + 'UpdateOnly' = $updateOnly + 'TargetVersion' = $row.Cells['TargetVersion'].Value + 'StopProcessInstall' = $row.Cells['StopProcessInstall'].Value + 'StopProcessUninstall' = $row.Cells['StopProcessUninstall'].Value + 'PreScriptInstall' = $row.Cells['PreScriptInstall'].Value + 'PostScriptInstall' = $row.Cells['PostScriptInstall'].Value + 'PreScriptUninstall' = $row.Cells['PreScriptUninstall'].Value + 'PostScriptUninstall' = $row.Cells['PostScriptUninstall'].Value + 'CustomArgumentListInstall' = $row.Cells['CustomArgumentListInstall'].Value + 'CustomArgumentListUninstall' = $row.Cells['CustomArgumentListUninstall'].Value + 'InstallIntent' = $row.Cells['InstallIntent'].Value + 'Notification' = $row.Cells['Notification'].Value + 'GroupID' = $row.Cells['GroupID'].Value + } + $selectedData += New-Object PSObject -Property $rowData } - $selectedData += New-Object PSObject -Property $rowData } - } - # Check if any valid data was extracted - if ($selectedData.Count -gt 0) { - $defaultFileName = "WinGet-WrapperImportGUI-$timestamp.csv" - $saveFileDialog = New-Object System.Windows.Forms.SaveFileDialog - $saveFileDialog.InitialDirectory = (Get-Location).Path - $saveFileDialog.FileName = $defaultFileName - $saveFileDialog.Filter = "CSV files (*.csv)|*.csv" + # Check if any valid data was extracted + if ($selectedData.Count -gt 0) { + $defaultFileName = "WinGet-WrapperImportGUI-$timestamp.csv" + $saveFileDialog = New-Object System.Windows.Forms.SaveFileDialog + $saveFileDialog.InitialDirectory = (Get-Location).Path + $saveFileDialog.FileName = $defaultFileName + $saveFileDialog.Filter = 'CSV files (*.csv)|*.csv' - $result = $saveFileDialog.ShowDialog() - if ($result -eq [System.Windows.Forms.DialogResult]::OK) { - $csvFilePath = $saveFileDialog.FileName - $selectedData | Export-Csv -Path $csvFilePath -NoTypeInformation - Write-ConsoleTextBox "Exported: $csvFilePath" - } else { - Write-ConsoleTextBox "No data exported." + $result = $saveFileDialog.ShowDialog() + if ($result -eq [System.Windows.Forms.DialogResult]::OK) { + $csvFilePath = $saveFileDialog.FileName + $selectedData | Export-Csv -Path $csvFilePath -NoTypeInformation + Write-ConsoleTextBox "Exported: $csvFilePath" + } + else { + Write-ConsoleTextBox 'No data exported.' + } + } + else { + Write-ConsoleTextBox 'No valid data to export.' } - } else { - Write-ConsoleTextBox "No valid data to export." } - } else { - Write-ConsoleTextBox "No data to export." - } -}) + else { + Write-ConsoleTextBox 'No data to export.' + } + }) # Event handler for moving selected rows $moveButton.Add_Click({ - $selectedRows = $dataGridView.SelectedRows - foreach ($row in $selectedRows) { - $name = $row.Cells['Name'].Value - $id = $row.Cells['ID'].Value - $version = $row.Cells['Version'].Value + $selectedRows = $dataGridView.SelectedRows + foreach ($row in $selectedRows) { + $name = $row.Cells['Name'].Value + $id = $row.Cells['ID'].Value + $version = $row.Cells['Version'].Value - # Add a new row to $dataGridViewSelected - $rowIndex = $dataGridViewSelected.Rows.Add() + # Add a new row to $dataGridViewSelected + $rowIndex = $dataGridViewSelected.Rows.Add() - # Set the "PackageID" column with the value from the selected row's "Name" column - $dataGridViewSelected.Rows[$rowIndex].Cells['PackageID'].Value = $id + # Set the "PackageID" column with the value from the selected row's "Name" column + $dataGridViewSelected.Rows[$rowIndex].Cells['PackageID'].Value = $id - # Set default values for other columns - $dataGridViewSelected.Rows[$rowIndex].Cells['Context'].Value = "Machine" - $dataGridViewSelected.Rows[$rowIndex].Cells['AcceptNewerVersion'].Value = "1" - $dataGridViewSelected.Rows[$rowIndex].Cells['UpdateOnly'].Value = "0" + # Set default values for other columns + $dataGridViewSelected.Rows[$rowIndex].Cells['Context'].Value = 'Machine' + $dataGridViewSelected.Rows[$rowIndex].Cells['AcceptNewerVersion'].Value = '1' + $dataGridViewSelected.Rows[$rowIndex].Cells['UpdateOnly'].Value = '0' - # Autosize columns in $dataGridViewSelected after adding rows and setting values - $dataGridViewSelected.AutoResizeColumns([System.Windows.Forms.DataGridViewAutoSizeColumnMode]::AllCells) + # Autosize columns in $dataGridViewSelected after adding rows and setting values + $dataGridViewSelected.AutoResizeColumns([System.Windows.Forms.DataGridViewAutoSizeColumnMode]::AllCells) - Write-ConsoleTextBox "Added '$id' to import list" + Write-ConsoleTextBox "Added '$id' to import list" - # Optionally remove the row from the original DataGridView - #$dataGridView.Rows.Remove($row) # Do not remove row after copy to selected datagridview - } -}) + # Optionally remove the row from the original DataGridView + #$dataGridView.Rows.Remove($row) # Do not remove row after copy to selected datagridview + } + }) # Function to write Column Definitions to ConsoleWriteBox Function GetColumnDefinitions { # Fetch the content of the README.md file - $url = "https://raw.githubusercontent.com/SorenLundt/WinGet-Wrapper/main/README.md" + $url = 'https://raw.githubusercontent.com/SorenLundt/WinGet-Wrapper/main/README.md' Write-ConsoleTextBox "$url" $response = Invoke-WebRequest -Uri $url @@ -594,20 +711,22 @@ Function GetColumnDefinitions { foreach ($column in $dataGridViewSelected.Columns) { $columnNames += $column.Name # Collect column names into an array } - Write-ConsoleTextBox "Column Name --> Description" - Write-ConsoleTextBox "****************************" + Write-ConsoleTextBox 'Column Name --> Description' + Write-ConsoleTextBox '****************************' # Loop through each column name foreach ($columnName in $columnNames) { # Use regex to find the line corresponding to the column name if ($content -match "\* $columnName\s*=\s*(.*?)
") { - $description = $matches[1] -replace "
", "`n" -replace "\* ", "" # Clean up the description + $description = $matches[1] -replace '
', "`n" -replace '\* ', '' # Clean up the description Write-ConsoleTextBox "$columnName --> $description" - } else { + } + else { Write-ConsoleTextBox "$columnName --> No description found." } } - Write-ConsoleTextBox "****************************" - } else { + Write-ConsoleTextBox '****************************' + } + else { Write-ConsoleTextBox "Failed to retrieve the README file. Status code: $($response.StatusCode)" } } @@ -629,7 +748,7 @@ function WinGetPackageDetails { # Output package details line by line to maintain formatting Write-ConsoleTextBox "$PackageID - Details:" $WingetPackageDetails -split "`r?`n" | ForEach-Object { Write-ConsoleTextBox $_ } - Write-ConsoleTextBox "_" # Separator for readability + Write-ConsoleTextBox '_' # Separator for readability # Optionally return the available versions array for further processing @@ -658,7 +777,8 @@ function WinGetPackageVersions { # Skip the first three lines and process the remaining lines foreach ($line in $versionLines[3..($versionLines.Length - 1)]) { $trimmedLine = $line.Trim() # Trim whitespace - if (-not [string]::IsNullOrWhiteSpace($trimmedLine) -and $trimmedLine -notmatch '^-+$') { # Check it's not empty or dashes + if (-not [string]::IsNullOrWhiteSpace($trimmedLine) -and $trimmedLine -notmatch '^-+$') { + # Check it's not empty or dashes $WinGetPackageVersions += $trimmedLine # Add to available versions array Write-ConsoleTextBox $trimmedLine # Display each version line } @@ -671,9 +791,9 @@ function WinGetPackageVersions { # Define a function to parse the search results function ParseSearchResults($searchResult) { - Write-ConsoleTextBox "Parsing data..." + Write-ConsoleTextBox 'Parsing data...' $parsedData = @() - $pattern = "^(.+?)\s+((?:[\w.-]+(?:\.[\w.-]+)+))\s+(\S.*?)\s*$" + $pattern = '^(.+?)\s+((?:[\w.-]+(?:\.[\w.-]+)+))\s+(\S.*?)\s*$' $searchResult -split "`n" | Where-Object { $_ -match $pattern } | ForEach-Object { $parsedName = $Matches[1].Trim() $parsedID = $Matches[2].Trim() @@ -682,12 +802,12 @@ function ParseSearchResults($searchResult) { # Add parsed and cleaned data to the result $parsedData += [PSCustomObject]@{ - 'Name' = $parsedName - 'ID' = $parsedID + 'Name' = $parsedName + 'ID' = $parsedID 'Version' = $parsedVersion } } - Write-ConsoleTextBox "Finished" + Write-ConsoleTextBox 'Finished' return $parsedData } @@ -703,34 +823,35 @@ function PerformSearch { if (![string]::IsNullOrWhiteSpace($searchString)) { Write-ConsoleTextBox "winget search --query $searchString --source WinGet --accept-source-agreements --disable-interactivity" $searchResult = @(winget search --query $searchString --source WinGet --accept-source-agreements --disable-interactivity) - # Splitting the search result into lines for logging purposes - $lines = $searchResult -split "`r`n" + # Splitting the search result into lines for logging purposes + $lines = $searchResult -split "`r`n" - # Writing each line to the consoleTextBox - foreach ($line in $lines) { - Write-ConsoleTextBox $line - } - if ($searchResult -contains "No package found matching input criteria.") { + # Writing each line to the consoleTextBox + foreach ($line in $lines) { + Write-ConsoleTextBox $line + } + if ($searchResult -contains 'No package found matching input criteria.') { $dataGridView.Rows.Clear() $searchErrorLabel.Text = "No WinGet package found for search query '$searchString'" } else { - # Clear existing rows from DataGridView - $dataGridView.Rows.Clear() + # Clear existing rows from DataGridView + $dataGridView.Rows.Clear() - # Parse the search result using the ParseSearchResults function - $parsedSearchResult = ParseSearchResults -searchResult $searchResult | - Where-Object { $null -ne $_.Name -and $_.Name -ne '' -and $_.Name.Trim() -ne '' } + # Parse the search result using the ParseSearchResults function + $parsedSearchResult = ParseSearchResults -searchResult $searchResult | + Where-Object { $null -ne $_.Name -and $_.Name -ne '' -and $_.Name.Trim() -ne '' } - # Add parsed data to DataGridView - $parsedSearchResult | ForEach-Object { - $row = $dataGridView.Rows.Add($_.Name, $_.ID, $_.Version) - } - $searchErrorLabel.Text = "Found $($dataGridView.RowCount) packages for '$searchString'" + # Add parsed data to DataGridView + $parsedSearchResult | ForEach-Object { + $row = $dataGridView.Rows.Add($_.Name, $_.ID, $_.Version) + } + $searchErrorLabel.Text = "Found $($dataGridView.RowCount) packages for '$searchString'" } - } else { + } + else { $dataGridView.Rows.Clear() - $searchErrorLabel.Text = "Please enter a search query." + $searchErrorLabel.Text = 'Please enter a search query.' } } @@ -741,167 +862,170 @@ $searchButton.Add_Click({ PerformSearch }) # Allow pressing Enter to trigger search $form.KeyPreview = $true $form.Add_KeyDown({ - param($keySender, $keyEvent) - if ($keyEvent.KeyCode -eq "Enter") { - PerformSearch - } -}) + param($keySender, $keyEvent) + if ($keyEvent.KeyCode -eq 'Enter') { + PerformSearch + } + }) # Event Handler for Get package details button $GetPackageDetails.Add_Click({ - $selectedRows = $dataGridView.SelectedRows - foreach ($row in $selectedRows) { - $id = $row.Cells['ID'].Value - WinGetPackageDetails -PackageID "$id" - } -}) + $selectedRows = $dataGridView.SelectedRows + foreach ($row in $selectedRows) { + $id = $row.Cells['ID'].Value + WinGetPackageDetails -PackageID "$id" + } + }) # Event Handler for Get package versions button $GetPackageVersions.Add_Click({ - $selectedRows = $dataGridView.SelectedRows - foreach ($row in $selectedRows) { - $id = $row.Cells['ID'].Value - WinGetPackageVersions -PackageID "$id" - } -}) + $selectedRows = $dataGridView.SelectedRows + foreach ($row in $selectedRows) { + $id = $row.Cells['ID'].Value + WinGetPackageVersions -PackageID "$id" + } + }) # Event handler for the "Import to InTune" button $InTuneimportButton.Add_Click({ - Write-ConsoleTextBox "Started import to InTune.." + Write-ConsoleTextBox 'Started import to InTune..' - # Check if $tenantIDTextBox.Text is empty, matches $tenantIDTextBoxDefaultText, or does not contain a dot - if ([string]::IsNullOrWhiteSpace($tenantIDTextBox.Text) -or $tenantIDTextBox.Text -eq $tenantIDTextBoxDefaultText -or -not ($tenantIDTextBox.Text -like '*.*')) { - Write-ConsoleTextBox "Please enter a valid Tenant ID before importing to InTune." - return # Stop further execution - } + # Check if $tenantIDTextBox.Text is empty, matches $tenantIDTextBoxDefaultText, or does not contain a dot + if ([string]::IsNullOrWhiteSpace($tenantIDTextBox.Text) -or $tenantIDTextBox.Text -eq $tenantIDTextBoxDefaultText -or -not ($tenantIDTextBox.Text -like '*.*')) { + Write-ConsoleTextBox 'Please enter a valid Tenant ID before importing to InTune.' + return # Stop further execution + } - # List of files to check - $filesToCheck = @( - "WinGet-Wrapper.ps1", - "WinGet-WrapperDetection.ps1", - "WinGet-WrapperRequirements.ps1", - "WinGet-WrapperImportFromCSV.ps1", - "IntuneWinAppUtil.exe" - ) + # List of files to check + $filesToCheck = @( + 'WinGet-Wrapper.ps1', + 'WinGet-WrapperDetection.ps1', + 'WinGet-WrapperRequirements.ps1', + 'WinGet-WrapperImportFromCSV.ps1', + 'IntuneWinAppUtil.exe' + ) + + $foundAllFiles = $true + foreach ($file in $filesToCheck) { + $fileFullPath = Join-Path -Path $scriptRoot -ChildPath $file + + if (-not (Test-Path -Path $fileFullPath -PathType Leaf)) { + # File not found, write a message to the console text box + Write-ConsoleTextBox "File '$file' was not found." + $foundAllFiles = $false + } + else { + # File found, write a message to the console text box + Write-ConsoleTextBox "File '$file' was found." + } + } + + if ($foundAllFiles) { + Write-ConsoleTextBox 'All required files found. Continue import to InTune...' + + # Export DataGridViewSelected to CSV - Save CSV Temporary + $selectedData = @() + + # Check if DataGridView is not empty + if ($dataGridViewSelected.Rows.Count -gt 0) { + # Create an empty array to store the selected data + $selectedData = @() + + # Iterate through DataGridView rows + foreach ($row in $dataGridViewSelected.Rows) { + $packageID = $row.Cells['PackageID'].Value + $context = $row.Cells['Context'].Value + $acceptNewerVersion = $row.Cells['AcceptNewerVersion'].Value + $updateOnly = $row.Cells['UpdateOnly'].Value + + # Check if all required values are not null or empty + if ($packageID -ne $null -and $packageID -ne '' -and + $context -ne $null -and $context -ne '' -and + $acceptNewerVersion -ne $null -and $acceptNewerVersion -ne '' -and + $updateOnly -ne $null -and $updateOnly -ne '') { + # Create a hashtable representing the row data and add it to the selected data array + $rowData = [ordered]@{ + 'PackageID' = $packageID + 'Context' = $context + 'AcceptNewerVersion' = $acceptNewerVersion + 'UpdateOnly' = $updateOnly + 'TargetVersion' = $row.Cells['TargetVersion'].Value + 'StopProcessInstall' = $row.Cells['StopProcessInstall'].Value + 'StopProcessUninstall' = $row.Cells['StopProcessUninstall'].Value + 'PreScriptInstall' = $row.Cells['PreScriptInstall'].Value + 'PostScriptInstall' = $row.Cells['PostScriptInstall'].Value + 'PreScriptUninstall' = $row.Cells['PreScriptUninstall'].Value + 'PostScriptUninstall' = $row.Cells['PostScriptUninstall'].Value + 'CustomArgumentListInstall' = $row.Cells['CustomArgumentListInstall'].Value + 'CustomArgumentListUninstall' = $row.Cells['CustomArgumentListUninstall'].Value + 'InstallIntent' = $row.Cells['InstallIntent'].Value + 'Notification' = $row.Cells['Notification'].Value + 'GroupID' = $row.Cells['GroupID'].Value + } + $selectedData += New-Object PSObject -Property $rowData + } + } + } + if ($selectedData -ne $null -and $selectedData.Count -gt 0) { + $fileName = "TempExport-$timestamp.csv" # Construct the filename with timestamp + $csvFilePath = Join-Path -Path $scriptRoot -ChildPath $fileName # Save to script root directory + $selectedData | Export-Csv -Path $csvFilePath -NoTypeInformation + Write-ConsoleTextBox "Exported: $csvFilePath" + } + else { + Write-ConsoleTextBox 'No data to export.' + return # Stop further execution + } - $foundAllFiles = $true - foreach ($file in $filesToCheck) { - $fileFullPath = Join-Path -Path $scriptRoot -ChildPath $file + # Prepare the Import script. + $logFile = "$scriptRoot\Logs\WinGet_WrapperImportFromCSV_$($TimeStamp).log" + $importScriptPath = Join-Path -Path $scriptRoot -ChildPath 'Winget-WrapperImportFromCSV.ps1' + Write-ConsoleTextBox "ImportScriptPath: $importScriptPath" + + #Inform user log file location: + Write-ConsoleTextBox '****************************************************' + Write-ConsoleTextBox "See log file for progress: $logFile" + Write-ConsoleTextBox '****************************************************' + + #Run The Import Script + # Define the arguments to be passed to the script + $arguments = "-csvFile `"$csvFilePath`" -TenantID $($tenantIDTextBox.Text) -ClientID $($clientIDTextBox.Text) -RedirectURL `"$($redirectURLTextBox.Text)`" -ScriptRoot `"$scriptRoot`" -SkipConfirmation -SkipModuleCheck" + Write-ConsoleTextBox "Arguments to be passed: $arguments" + #Set-ExecutionPolicy Bypass -Scope Process -ExecutionPolicy Bypass -Force + Start-Process powershell -ArgumentList '-NoProfile', '-ExecutionPolicy Bypass', "-File `"$importScriptPath`"", $arguments -Wait -NoNewWindow + + # Run Update-GUIFromLogFile in the main thread + Start-Sleep -Seconds 5 # wait log file creation before reading it + Update-GUIFromLogFile -logFilePath "$logFile" + + # Remove TempExport-$timestamp.csv + if (Test-Path $csvFilePath) { + Remove-Item $csvFilePath -Force + Write-ConsoleTextBox "File $csvFilePath deleted successfully." + } + else { + Write-ConsoleTextBox "File $csvFilePath not found." + } - if (-not (Test-Path -Path $fileFullPath -PathType Leaf)) { - # File not found, write a message to the console text box - Write-ConsoleTextBox "File '$file' was not found." - $foundAllFiles = $false + Write-ConsoleTextBox '****************************************************' + Write-ConsoleTextBox "Import Log File: $logFile" + Write-ConsoleTextBox '****************************************************' } else { - # File found, write a message to the console text box - Write-ConsoleTextBox "File '$file' was found." + Write-ConsoleTextBox 'Not all required files were found. Code will not run.' } - } - - if ($foundAllFiles) { - Write-ConsoleTextBox "All required files found. Continue import to InTune..." - -# Export DataGridViewSelected to CSV - Save CSV Temporary -$selectedData = @() - -# Check if DataGridView is not empty -if ($dataGridViewSelected.Rows.Count -gt 0) { - # Create an empty array to store the selected data - $selectedData = @() - - # Iterate through DataGridView rows - foreach ($row in $dataGridViewSelected.Rows) { - $packageID = $row.Cells['PackageID'].Value - $context = $row.Cells['Context'].Value - $acceptNewerVersion = $row.Cells['AcceptNewerVersion'].Value - $updateOnly = $row.Cells['UpdateOnly'].Value - - # Check if all required values are not null or empty - if ($packageID -ne $null -and $packageID -ne '' -and - $context -ne $null -and $context -ne '' -and - $acceptNewerVersion -ne $null -and $acceptNewerVersion -ne '' -and - $updateOnly -ne $null -and $updateOnly -ne '') { - # Create a hashtable representing the row data and add it to the selected data array - $rowData = [ordered]@{ - 'PackageID' = $packageID - 'Context' = $context - 'AcceptNewerVersion' = $acceptNewerVersion - 'UpdateOnly' = $updateOnly - 'TargetVersion' = $row.Cells['TargetVersion'].Value - 'StopProcessInstall' = $row.Cells['StopProcessInstall'].Value - 'StopProcessUninstall' = $row.Cells['StopProcessUninstall'].Value - 'PreScriptInstall' = $row.Cells['PreScriptInstall'].Value - 'PostScriptInstall' = $row.Cells['PostScriptInstall'].Value - 'PreScriptUninstall' = $row.Cells['PreScriptUninstall'].Value - 'PostScriptUninstall' = $row.Cells['PostScriptUninstall'].Value - 'CustomArgumentListInstall' = $row.Cells['CustomArgumentListInstall'].Value - 'CustomArgumentListUninstall' = $row.Cells['CustomArgumentListUninstall'].Value - 'InstallIntent' = $row.Cells['InstallIntent'].Value - 'Notification' = $row.Cells['Notification'].Value - 'GroupID' = $row.Cells['GroupID'].Value - } - $selectedData += New-Object PSObject -Property $rowData - } - } -} - if ($selectedData -ne $null -and $selectedData.Count -gt 0) { - $fileName = "TempExport-$timestamp.csv" # Construct the filename with timestamp - $csvFilePath = Join-Path -Path $scriptRoot -ChildPath $fileName # Save to script root directory - $selectedData | Export-Csv -Path $csvFilePath -NoTypeInformation - Write-ConsoleTextBox "Exported: $csvFilePath" - } else { - Write-ConsoleTextBox "No data to export." - return # Stop further execution - } - - # Prepare the Import script. - $logFile = "$scriptRoot\Logs\WinGet_WrapperImportFromCSV_$($TimeStamp).log" - $importScriptPath = Join-Path -Path $scriptRoot -ChildPath "Winget-WrapperImportFromCSV.ps1" - Write-ConsoleTextBox "ImportScriptPath: $importScriptPath" - - #Inform user log file location: - Write-ConsoleTextBox "****************************************************" - Write-ConsoleTextBox "See log file for progress: $logFile" - Write-ConsoleTextBox "****************************************************" - - #Run The Import Script - # Define the arguments to be passed to the script - $arguments = "-csvFile `"$csvFilePath`" -TenantID $($tenantIDTextBox.Text) -LogFile `"$logFile`" -ScriptRoot `"$scriptRoot`" -SkipConfirmation -SkipModuleCheck" - Write-ConsoleTextBox "Arguments to be passed: $arguments" - #Set-ExecutionPolicy Bypass -Scope Process -ExecutionPolicy Bypass -Force - Start-Process powershell -ArgumentList "-NoProfile", "-ExecutionPolicy Bypass", "-File `"$importScriptPath`"", $arguments -Wait -NoNewWindow - - # Run Update-GUIFromLogFile in the main thread - Start-Sleep -Seconds 5 # wait log file creation before reading it - Update-GUIFromLogFile -logFilePath "$logFile" - - # Remove TempExport-$timestamp.csv - if (Test-Path $csvFilePath) { - Remove-Item $csvFilePath -Force - Write-ConsoleTextBox "File $csvFilePath deleted successfully." - } else { - Write-ConsoleTextBox "File $csvFilePath not found." - } - - Write-ConsoleTextBox "****************************************************" - Write-ConsoleTextBox "Import Log File: $logFile" - Write-ConsoleTextBox "****************************************************" - } else { - Write-ConsoleTextBox "Not all required files were found. Code will not run." - } -}) + }) # Update ConsoleProgress -Show-ConsoleProgress -PercentComplete 100 -Status "Sucessfully loaded Winget-Wrapper Import GUI" +Show-ConsoleProgress -PercentComplete 100 -Status 'Sucessfully loaded Winget-Wrapper Import GUI' # Greeting -Write-ConsoleTextBox "****************************************************" -Write-ConsoleTextBox " WinGet-Wrapper" -Write-ConsoleTextBox " https://github.com/SorenLundt/WinGet-Wrapper" -Write-ConsoleTextBox "" -Write-ConsoleTextBox " GNU General Public License v3" -Write-ConsoleTextBox "****************************************************" +Write-ConsoleTextBox '****************************************************' +Write-ConsoleTextBox ' WinGet-Wrapper' +Write-ConsoleTextBox ' https://github.com/SorenLundt/WinGet-Wrapper' +Write-ConsoleTextBox '' +Write-ConsoleTextBox ' GNU General Public License v3' +Write-ConsoleTextBox '****************************************************' # Show form $form.ShowDialog() | Out-Null \ No newline at end of file