Skip to main content

Simplify iMessage File Extraction with iMessageExporter

· 3 min read
Hannes Palmquist
Senior Consultant Cloud

iMessage is a fantastic platform for communication, but when it comes to extracting your precious photos, videos, and other files, the process can quickly become daunting. Instead of paying for expensive third-party services, you can take control of your data with the iMessageExporter script. This handy tool simplifies the extraction process, making it free and easy for anyone to use. Here’s how you can make the most of this tool.

What is iMessageExporter?

iMessageExporter is a straightforward PowerShell script that enables users to extract media files, such as photos and videos, from their iMessage backups. The script is designed to save you time and money by providing a free alternative to commercial services that charge for the same task. Whether you're switching phones, archiving memories, or just want to have a backup of your media, iMessageExporter makes it easy.

Step-by-Step Guide: How to Use iMessageExporter

To get started with iMessageExporter, follow these simple steps:

  1. Backup Your iPhone with iTunes Before you can extract any files, you'll need to create a backup of your iPhone using iTunes. Here’s how:

    • Connect your iPhone to your PC or Mac using a USB cable.
    • Open iTunes and select your device when it appears in the top-left corner.
    • Create a backup by clicking on "Back Up Now."
    • Important: Ensure that the backup is not encrypted. This is crucial because iMessageExporter won’t be able to access the data from an encrypted backup.
  2. Locate the iTunes Backup on Your Computer Once the backup is complete, you can locate it on your computer. The default location for the backup depends on your operating system:

    • Windows: C:\Users<username>\Apple\MobileSync\Backup
    • Mac: ~/Library/Application Support/MobileSync/Backup/
  3. Run the iMessageExporter Script With your backup in place, it's time to run the iMessageExporter script. Here’s how:

    • Download and open PowerShell on your computer.
    • Run the script using the following command, replacing the paths with your specific directories:
.\iMessageExporter -iTunesBackupDirectory 'C:\Users\John\Apple\MobileSync\Backup\12345678-1234567890ABCDEF' -ExportDirectory 'C:\Export'

In this command:

  • -iTunesBackupDirectory specifies the path to your iTunes backup.
  • -ExportDirectory defines the folder where you want the extracted files to be saved.

After running the script, you’ll see the files being extracted into your chosen directory. These files could include JPG, HEIC, and other media formats.

Setting Up Dependencies

Before running iMessageExporter, make sure you have the necessary dependencies installed. The script relies on the PowerShell module PSSQLite to interact with the iTunes backup database. You can install it easily using the following command in PowerShell:

Install-Module PSSQLite -Scope CurrentUser

This command installs the module for your current user, ensuring that iMessageExporter can run smoothly.

Acknowledgments

iMessageExporter is built upon the foundation laid by basnijholt, who created a Perl script for exporting iMessages to HTML. While his original script focused on full message exports, iMessageExporter is streamlined to focus on extracting files only. By converting the logic from Perl to PowerShell, iMessageExporter caters to users who are specifically interested in retrieving their media files.

Conclusion

iMessageExporter offers a simple and cost-effective way to extract your iMessage photos, videos, and other files. By following the steps outlined above, you can easily take control of your media without needing to rely on expensive third-party services. Whether you’re tech-savvy or just getting started, iMessageExporter makes the process straightforward, allowing you to preserve your digital memories effortlessly.

Give it a try, and see how easy it can be to manage your iMessage files!

Enable exchange delegates to schedule teams meetings

· 4 min read
Hannes Palmquist
Senior Consultant Cloud

In today's interconnected workplace, seamless collaboration is essential. One common challenge that arises is when a delegate tries to schedule a meeting on behalf of another user (the delegator) and encounters an error when attaching a Teams meeting in Outlook. The error message, "Unable to connect to the server, please try again later," can be both confusing and disruptive.

This issue affects users whose mailboxes are hosted on-premises within an Exchange hybrid environment. While the Exchange hybrid configuration is working and the Teams calendar for on-premises mailboxes is functional, this specific error persists.

Understanding the Root Cause

The underlying reason for this issue is the absence of a necessary PartnerApplication in the on-premises Exchange server for Skype for Business Online. This application is crucial for enabling the Teams service to generate meeting links for users who are scheduling meetings on behalf of others. Without it, the delegate is unable to successfully create a Teams meeting. This PartnerApplication is not configured as part of the Exchange Hybrid setup wizard nor in the procedure to configure a Skype for Business hybrid.

The steps to configure this PartnerApplication are well-documented in official Microsoft resources. However, there have been some errors in the conversion of PowerShell script code from the deprecated MSOnline (MSOL) module to Microsoft Graph (MSGraph). This conversion appears to have been done without proper testing, and is as of now not working.

In this blog post, we will walk you through the correct steps to configure the PartnerApplication using the MSOL module, as it has proven to be more reliable in this scenario.

Important

Before proceeding, it's important to ensure that the delegate has been assigned the "Editor" role. Assigning the "Owner" role may seem like a viable option, but it does not work in this context.

Step 1: Create a New Mail User Account for the Skype for Business Online Partner Application

This initial step involves creating a mail user on the Exchange server and assigning the appropriate management role rights. This account will be used later in the process.

Here’s how you can do it:

$user = New-MailUser -Name SfBOnline-ApplicationAccount -ExternalEmailAddress SfBOnline-ApplicationAccount@casiad.com
Set-MailUser -Identity $user.Identity -HiddenFromAddressListsEnabled $True
New-ManagementRoleAssignment -Role UserApplication -User $user.Identity
New-ManagementRoleAssignment -Role ArchiveApplication -User $user.Identity

Step 2: Create and Enable a Partner Application for Skype for Business Online

Next, you need to create a new partner application and link it to the mail user account you just created. Run the following command in Exchange PowerShell within your on-premises Exchange organization:

New-PartnerApplication -Name SfBOnline -ApplicationIdentifier 00000004-0000-0ff1-ce00-000000000000 -Enabled $True -LinkedAccount $user.Identity

Step 3: Export the On-Premises Authorization Certificate

The next step involves exporting the on-premises authorization certificate, which will later be imported into your Skype for Business Online organization:

$thumbprint = (Get-AuthConfig).CurrentCertificateThumbprint
if((test-path $env:SYSTEMDRIVE\OAuthConfig) -eq $false) {
md $env:SYSTEMDRIVE\OAuthConfig
}
cd $env:SYSTEMDRIVE\OAuthConfig
$oAuthCert = (dir Cert:\LocalMachine\My) | where {$_.Thumbprint -match $thumbprint}
$certType = [System.Security.Cryptography.X509Certificates.X509ContentType]::Cert
$certBytes = $oAuthCert.Export($certType)
$CertFile = "$env:SYSTEMDRIVE\OAuthConfig\OAuthCert.cer"
[System.IO.File]::WriteAllBytes($CertFile, $certBytes)

Step 4: Upload the On-Premises Authorization Certificate to Microsoft Entra ACS

This is the critical step where issues have been noted when using the MSGraph module. The following MSOL module code is known to work correctly:

Important

The MSOnline module is only compatible with Windows Powershell. (It is not compatible with Powershell Core)

Install-Module MSOnline -Scope CurrentUser
Connect-MsolService
$CertFile = "$env:SYSTEMDRIVE\OAuthConfig\OAuthCert.cer"
$objFSO = New-Object -ComObject Scripting.FileSystemObject
$CertFile = $objFSO.GetAbsolutePathName($CertFile);
$cer = New-Object System.Security.Cryptography.X509Certificates.X509Certificate
$cer.Import($CertFile)
$binCert = $cer.GetRawCertData();
$credValue = [System.Convert]::ToBase64String($binCert)
$ServiceName = "00000004-0000-0ff1-ce00-000000000000"
$p = Get-MsolServicePrincipal -AppPrincipalId $ServiceName
New-MsolServicePrincipalCredential -ServicePrincipalName $p.AppPrincipalId -Type Asymmetric -Usage Verify -Value $credValue

Step 5: Verify the Certificate Upload

Finally, verify that the certificate has been successfully uploaded to the Skype for Business service principal:

Get-MsolServicePrincipalCredential -AppPrincipalId $p.AppPrincipalId -ReturnKeyValues $true | select *

Conclusion

By carefully following these steps using the MSOL module, you can resolve the delegate scheduling error and ensure smooth integration between on-premises Exchange and Microsoft Teams. While the shift to MSGraph is on the horizon, the MSOL module remains a reliable solution for this particular issue.

Stay tuned for future updates as we continue to explore the best practices for maintaining a seamless hybrid environment.

Work with the Immich API from Powershell

· 2 min read
Hannes Palmquist
Senior Consultant Cloud

I've put together a new powershell module which allows you to work with the Immich API. With the API easily accessible you can now write automations for your image gallery. The module has approx 85% API coverage where the remaining 15% is mainly used by the Immich Web application and or mobile app.

You can manage users, assets, albums, libraries, partners, api-keys, activities, configuration, start jobs, sharing links, tags etc.

You can build quite powerful automations for your image gallery, some examples;

  • Automatically create and update albums based on folder structure, exif metadata like tags/keywords
    • For instance, I have a filewatcher script that monitors my on-disk image library, if an image is written/modified on disk, the image keywordw is retrieved with exiftool and if the image has a keyword beginning with "Album_*" it extract the album name, makes sure the album exist in Immich and then makes sure the image is a member of that album. With this script I can update keywords in an external application (in my case Adobe Lightroom) and have those changes reflected in Immich. I plan on publishing a blog post with more details about this setup.
  • Download/Upload assets
  • Hide/Trash/Favorite assets
  • Manage album/asset sharing
  • With a filewatcher you can instruct Immich to refresh thumbnails and/or metadata for an external asset when it is updated/changed.
Install-Module PSImmich -Scope CurrentUser

PSImmich Module Docs

Find Office 365 URL and IP

· 2 min read
Hannes Palmquist
Senior Consultant Cloud

Recently i published a new module PSDev with the purpose to group together a set of utility functions. Most of the functions are stand-alone and can be used independently of the module. The module is published to PSGallery for ease of access.

Install-Module PSDev -Scope CurrentUser

PSDev Module Docs

Function: Get-Office365IPURL

The first addition to the module is the Get-Office365IPURL and Test-Office365IPURL functions. These functions simplify the process of getting a list of firewall rules for a given set of services and troubleshoot communication issues.

Get-Office365IPURL is used to get a detailed list of the rules. The Office 365 website combines, protocol, port and type of openings. This function will expand these rules based on these attributes. See the example below.

Get-Office365IPURL -Services Exchange -Types IP4,URL | Where-Object {$_.Required -eq $true}

Group Service Type Protocol Port Endpoint Required
----- ------- ---- -------- ---- -------- --------
Exchange_TCP_25_IP Exchange IP4 TCP 25 52.100.0.0/14 True
Exchange_TCP_25_IP Exchange IP4 TCP 25 104.47.0.0/17 True
Exchange_TCP_25_IP Exchange IP4 TCP 25 40.107.0.0/16 True
Exchange_TCP_25_IP Exchange IP4 TCP 25 40.92.0.0/15 True
Exchange_TCP_443_IP Exchange IP4 TCP 443 40.96.0.0/13 True
Exchange_TCP_443_IP Exchange IP4 TCP 443 204.79.197.215/32 True
Exchange_TCP_25_URL Exchange URL TCP 25 *.mail.protection.outlook.com True
...

Get-Office365IPURL Docs

Function: Test-Office365IPURL

Test-Office365IPURL is used to test weather a IP address is included within the ipranges provided by Microsoft. This could be useful of the firewall logs shows that a connection to an IP adress is blocked and there is a need to verify if that IP belongs to the ranges provided by Microsoft. See the example below.


Test-Office365IPURL -IP 52.109.76.22 | Where-Object {$_.ismember -eq $true} | Format-Table

RuleID ServiceArea TCPPort UDPPort Required Range Subject IsMember
------ ----------- ------- ------- -------- ----- ------- --------
46 Common 80,443 True 52.108.0.0/14 52.109.76.22 True
64 Common 443 True 52.108.0.0/14 52.109.76.22 True
65 Common 80,443 True 52.108.0.0/14 52.109.76.22 True

Test-Office365IPURL Docs

Cleanup GitHub Artifacts

· 2 min read
Hannes Palmquist
Senior Consultant Cloud
info

This script has been integrated in the module PSDev and is no longer provided as a stand-alone script.

At the time of writing this post there is no native automated way to cleanup/remove github artifacts produced within GitHub Action Workflows. If you for instance have an automated build process you will quite fast hit the free storage quota in GitHub and you'll have to start paying for additional storage. There are a few available options to manage this. You could manuallly remove each workflow run that could contain artifacts. This could be timeconsuming work. You could also configure the retension time of workflows in each repo. However both of these will remove the logs of each workflow run as well. A better way if you don't need the artifacts after the workflow run is to add a cleanup job to the workflow. I've been using geekyeggo/delete-artifact@v2. This action till remove the artifacts that i specify in the workflow file automatically within a cleanup job at the end of the workflow. This works great for future workflow runs once you configure the cleanup job. But what about if you have hit the storage quota and need to cleanup all existing artifacts? Then you would have to do it manually or call the GitHub Rest API and remove all artifacts. This is what the below script does, it will enumerate all artifacts for a specific repo or all repos for a user account and remove all artifacts.

Remove-GitHubArtifact -GitHubSecret "ABC" -GitHubOrg "user"

Repo Artifacts_Found Artifacts_Removed Artifacts_SizeMB
---- --------------- ----------------- ----------------
PSDaikin 5 5 43
PSDataSet 2 2 2
PSMaintenanceManager 2 2 21
PSPortainer 34 34 321
PSQueue 0 0 0
PSScriptInfo 0 0 0
PSSort 0 0 0

Or for a specific repo:

Remove-GitHubArtifact -GitHubSecret "ABC" -GitHubOrg "user" -Repo "PSMaintenanceManager"

Repo Artifacts_Found Artifacts_Removed Artifacts_SizeMB
---- --------------- ----------------- ----------------
PSMaintenanceManager 2 2 21
danger

The script will remove all artifacts for the specified repo or all repos on the account. This is destructive and can not be reversed.

Announcing PSPortainer Powershell Module

· One min read
Hannes Palmquist
Senior Consultant Cloud

Some time ago I wanted to automate a process where I needed check status of a few docker containers managed with Portainer and noticed that there was no powershell module available on the gallery for portainer. A couple of minutes later I had discovered the Portainer Rest API and though that it could be a fun project to provide powershell users with the ability to manage their Portainer and Docker instances with powershell.

So here it is, an early pre-release/work in progress powershell module for Portainer, PSPortainer

If you want to contribute to the project it is publically available on GitHub here

To get started, visit the docs for the module at getps.dev or start exploring directly by installing the module from PSGallery

Install-Module PSPortainer -Scope CurrentUser

Setup Azure App for Exchange Online unattended access for scripts

· 5 min read
Hannes Palmquist
Senior Consultant Cloud
info

This script has been integrated in the module PSDev and is no longer provided as a stand-alone script.

Microsoft has recently released (GA) version 3.0.0 of the ExchangeOnlineManagement powershell module. One of the new features is certificate based authentication which will allow unattended scripts to authenticate with Exchange Online without an interactive login prompt. Up until now you had to use basic authentication to connect to Exchange Online unattended.

Microsoft has also published documentation with all steps required to set this up. To simplify this process I wrote the script CreateEXOUnattendedAzureApp.ps1 which walks you through the process.

Picture1

Connect to Exchange Online using a certificate

You can connect to Exchange Online with a certificate in three ways.

  • Passing a certificate object to Connect-ExchangeOnline
  • Providing the thumbprint of the certificate. In this case the certificate must be stored in Windows Certificate Store under CurrentUser\My
  • And last by providing the path to the pfx-file and the password

By Certificate object

$Cert = Get-Item cert:\CurrentUser\My\'<thumbprint>'
Connect-ExchangeOnline -Certificate $Cert -AppId '<appid>'

By Certificate thumbprint

Connect-ExchangeOnline -CertificateThumbprint '<thumbprint>' -AppId '<appid>'

By Certificate file

Connect-ExchangeOnline -CertificateFilePath '<path to file.pfx' -CertificatePassword (ConvertTo-SecureString -String '<password>' -AsPlainText -Force) -AppId '<appid>'

Considerations for unattended scripts

In the case where you run a script as a service account with Task Scheduler for instance I would recommend to use the thumbprint method and make sure the certificate is stored in the Windows Certificate Store (This script imports the certificate to the store automatically). In this case you would not need to care about handling passwords for the certificate pfx file. Access to the certificate is based on the fact that the process running the script is authenicated as the service account which is the only account that can access the certificates in the users CurrentUser\My store. Make sure that you import the certificate to the Certificate Store of the service account. This can be acheived by running mmc.exe "as a different user" and adding the certificate snapin.

In case the script runs on linux the thumbprint method is not an option, instead use the certificate by object or file methods.

Script

important

The script is available on github where you are welcome to contribute or report issues.

<#PSLicenseInfo
Copyright © 2022 Hannes Palmquist

Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be included in all copies
or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.

PSLicenseInfo#>
<#PSScriptInfo
{
"VERSION": "1.0.0.0",
"GUID": "7fef8b41-e91d-4cb0-b656-1201c3820eb8",
"FILENAME": "CreateEXOUnattendedAzureApp.ps1",
"AUTHOR": "Hannes Palmquist",
"AUTHOREMAIL": "[email protected]",
"CREATEDDATE": "2022-10-04",
"COMPANYNAME": "N/A",
"COPYRIGHT": "© 2022, Hannes Palmquist, All Rights Reserved"
}
PSScriptInfo#>

[CmdletBinding()]
param (
[Parameter(Mandatory)][string]$Organization,
[Parameter(Mandatory)][string]$OutputDirectory,
[Parameter()][string]$AppName = 'ExchangeScriptAccess',
[Parameter][switch]$PassThru
)

$ErrorActionPreference = 'Stop'

$SavedVerbosePreference = $VerbosePreference
$VerbosePreference = 'SilentlyContinue'
Import-Module Microsoft.Graph.Applications, Microsoft.Graph.Authentication, Microsoft.Graph.DeviceManagement.Enrolment -Verbose:$false
$VerbosePreference = $SavedVerbosePreference

function Get-RandomPassword
{
param (
[int]$length = 25
)
$Chars = [char[]]([char]33..[char]95) + ([char[]]([char]97..[char]126)) + 0..9
$Scramble = $Chars | Sort-Object { Get-Random }
return ($Scramble[0..$length] -join '')
}

$ResultObjectHash = [ordered]@{
Organization = $Organization
OutputDirectory = $OutputDirectory
AppName = $AppName
Certificate = $null
CertificatePassword = Get-RandomPassword
CertificatePFXPath = (Join-Path -Path $OutputDirectory -ChildPath "$Organization.pfx")
CertificateCERPath = (Join-Path -Path $OutputDirectory -ChildPath "$Organization.cer")
}

$null = Connect-Graph -Scopes 'Application.ReadWrite.All', 'RoleManagement.ReadWrite.Directory'

$ResultObjectHash.Certificate = New-SelfSignedCertificate -DnsName $ResultObjectHash.Organization -CertStoreLocation 'cert:\CurrentUser\My' -NotAfter (Get-Date).AddYears(1) -KeySpec KeyExchange
Write-Verbose "Created self-signed certificate with thumbprint: $($ResultObjectHash.Certificate.Thumbprint)"

$null = $ResultObjectHash.Certificate | Export-PfxCertificate -FilePath $ResultObjectHash.CertificatePFXPath -Password (ConvertTo-SecureString -String $ResultObjectHash.CertificatePassword -AsPlainText -Force)
Write-Verbose "Exported certificate with private key (pfx) to: $($ResultObjectHash.CertificatePFXPath)"

$null = $ResultObjectHash.Certificate | Export-Certificate -FilePath $ResultObjectHash.CertificateCERPath
Write-Verbose "Exported certificate with public key (cer) to: $($ResultObjectHash.CertificateCERPath)"

$Web = [Microsoft.Graph.PowerShell.Models.MicrosoftGraphWebApplication]::New()
$Web.RedirectUris = 'https://localhost'
Write-Verbose 'Initialized MicrosoftGraphWebApplication'

$ResourceAccess = [Microsoft.Graph.PowerShell.Models.MicrosoftGraphResourceAccess]::New()
$ResourceAccess.Id = 'dc50a0fb-09a3-484d-be87-e023b12c6440'
$ResourceAccess.Type = 'Role'
Write-Verbose 'Initialized MicrosoftGraphResourceAccess'

$RequiredResourceAccess = [Microsoft.Graph.PowerShell.Models.MicrosoftGraphRequiredResourceAccess]::New()
$RequiredResourceAccess.ResourceAccess = $ResourceAccess
$RequiredResourceAccess.ResourceAppId = '00000002-0000-0ff1-ce00-000000000000'
Write-Verbose 'Initialized MicrosoftGraphRequiredResourceAccess'

$KeyCred = [Microsoft.Graph.PowerShell.Models.MicrosoftGraphKeyCredential]::New()
$keycred.DisplayName = $ResultObjectHash.Organization
$KeyCred.Key = $ResultObjectHash.Certificate.RawData
$KeyCred.KeyId = $ResultObjectHash.Certificate.SerialNumber
$KeyCred.StartDateTime = $ResultObjectHash.Certificate.NotBefore
$KeyCred.EndDateTime = $ResultObjectHash.Certificate.NotAfter
$KeyCred.Usage = 'Verify'
$KeyCred.Type = 'AsymmetricX509Cert'
Write-Verbose 'Initialized MicrosoftGraphKeyCredential'

$ResultObjectHash.AzureAppRegistration = New-MgApplication `
-DisplayName $ResultObjectHash.AppName `
-Description 'Used by automations that need access to exchange online' `
-SignInAudience AzureADMyOrg `
-Web $Web `
-RequiredResourceAccess $RequiredResourceAccess `
-KeyCredentials $KeyCred
Write-Verbose "Created Azure App: $($ResultObjectHash.AppName)"

$ResultObjectHash.ServicePrincipal = New-MgServicePrincipal -AppId $ResultObjectHash.AzureAppRegistration.AppId

Write-Verbose 'Waiting 60 seconds for Azure app to be provisioned...'
Start-Sleep -Seconds 60
Start-Process "https://login.microsoftonline.com/$($ResultObjectHash.Organization)/adminconsent?client_id=$($ResultObjectHash.AzureAppRegistration.Appid)"
$null = Read-Host ' Press enter once consent has been given'

$null = New-MgRoleManagementDirectoryRoleAssignment -PrincipalId $ResultObjectHash.ServicePrincipal.id -RoleDefinitionId '29232cdf-9323-42fd-ade2-1d097af3e4de' -DirectoryScopeId /
Write-Verbose 'Added role assignment'

if ($PassThru)
{
Write-Output ([pscustomobject]$ResultObjectHash)
}
else
{
Write-Host ''
Write-Host ' Use the following command to connect Exchange Online:'
Write-Host ''
Write-Host -ForegroundColor Cyan "Connect-ExchangeOnline -CertificateThumbprint `"$($ResultObjectHash.Certificate.Thumbprint)`" -AppId `"$($ResultObjectHash.AzureAppRegistration.AppId)`" -Organization `"$($ResultObjectHash.Organization)`""
Write-Host ''
Write-Host ' NOTE: Restart powershell before connecting to Exchange Online' -ForegroundColor Yellow
Write-Host ' NOTE: It could take some time before the added roles are effective. If you get an error regarding missing permissions, please wait a minute and try again.' -ForegroundColor Yellow
Write-Host ''
}

Remove-Variable ResultObjectHash -ErrorAction SilentlyContinue

Unable to write certain characters in Windows Terminal

· One min read
Hannes Palmquist
Senior Consultant Cloud

Recently I noticed a strange issue within Windows Terminal where I was unable to write the "$" sign using Ctrl+Alt+4. (Swedish keyboard layout has Ctrl+Alt+4 as the key combination to write a $ sign). However a workaround was to use Altgr+4 instead which worked fine. This issue was isolated to Windows Terminal as there were no issue writing $ in any other application, ie, notepad, vscode etc.

Luckely the issue for me was simple, with some update to Windows Terminal the development team hi-jacked the shortcut Ctrl+Alt+4 for changing to tab number 3. I removed the shortcut keybinding from the settings page and vola, Ctrl+Alt+4 started working as a $-dollar sign again.

Settings -> Actions -> Look for a shortcut for the key combination that is not working.

The same issue would arise for all keyboard layouts using Ctrl+Alt+X for a character.

In the case of Scandinavian keyboard layouts the following characters is probably affected.

  • Ctrl+Alt+2 -> @
  • Ctrl+Alt+3 -> £
  • Ctrl+Alt+4 -> $
  • Ctrl+Alt+7 -> {
  • Ctrl+Alt+8 -> [
  • Ctrl+Alt+9 -> ]

I though I'd share if anyone else stumbles upon this.

Introducing PSQueue

· One min read
Hannes Palmquist
Senior Consultant Cloud

Recently I developed a tool that utilizes the .NET class system.collections.queue. The function runs continously and produces workitems that should be processed in sequence and in the same order they were added. One simple way to acheive this is to use the collection queue. This class provides a simple way to add items to the queue and retrieve the oldest item when needed.

For fun I wanted to create a wrapper for the queue class so that it can be used in a powershell style syntax. Additionally i missed functionality to see the rate and velocity that items were added and removed to the queue.

Queue objects created with this module contains metrics for count of added and removed items, rate of added and removed items and velocity.

Repo
Docs
PowerShell Gallery