Mert Özen Further With Every Line

Blog

Mert Özen's blog posts on software development, backend, frontend, and DevOps.

Series
247 posts found
Testing Scripts and Running Them in CI: Pester 6, PSScriptAnalyzer, Cross-Platform and Moving from 5.1 to 7.x
DevOps PART 08

Testing Scripts and Running Them in CI: Pester 6, PSScriptAnalyzer, Cross-Platform and Moving from 5.1 to 7.x

In GitHub Actions, a shell: pwsh step only adds $ErrorActionPreference = 'stop'; even if dotnet test fails in the middle, the step stays green when the last native command returns 0, so keep the run block a single script call. Pester 6 tests and mocks for Bookstore.Ops, PSScriptAnalyzer rules, a Windows and Ubuntu matrix, cross-platform traps, and the differences when moving from 5.1 to 7.x and from 7.6 to 7.7.

15 Nov 2026 16 min 7
Managing Remote Servers: SSH-Based Remoting, Invoke-Command, Sessions and Keeping Credentials Out of Scripts
DevOps PART 07

Managing Remote Servers: SSH-Based Remoting, Invoke-Command, Sessions and Keeping Credentials Out of Scripts

In PowerShell remoting, the objects returned by Invoke-Command are serialized copies: properties come back, methods do not; do the remote work inside the script block. SSH-based remoting, $using:, sessions, the second hop, reading secrets from a vault with SecretManagement, and a rollout script that deploys Bookstore.Api to two servers one by one and stops at the first failure.

15 Nov 2026 13 min 8
Real Work: File System, REST APIs, JSON/CSV, Scheduled Tasks, Windows Services, IIS and Network Diagnostics on Windows
DevOps PART 06

Real Work: File System, REST APIs, JSON/CSV, Scheduled Tasks, Windows Services, IIS and Network Diagnostics on Windows

ConvertTo-Json only goes 2 levels deep by default; a nested body sent to an API silently turns into the string "System.Collections.Hashtable", so pass -Depth to every body. Bearer tokens, -MaximumRetryCount retrying a POST even on 401, $PSScriptRoot and CSV encoding, Windows Services, scheduled tasks, IIS and network commands, and finally a deploy script for Bookstore.Api with a backup and a way back.

15 Nov 2026 16 min 8
From Functions to Modules: Advanced Functions, [CmdletBinding()], Parameter Validation, Pipeline Input and -WhatIf
DevOps PART 05

From Functions to Modules: Advanced Functions, [CmdletBinding()], Parameter Validation, Pipeline Input and -WhatIf

In PowerShell, a function's result is not its return value but everything that lands on the success stream; advanced functions ([CmdletBinding()]) let you manage that, parameter validation, pipeline input and -WhatIf/-Confirm like a cmdlet. We write the Bookstore.Ops module with its manifest, show preferences that do not reach a module and the ShouldProcess trap in CI, and install it from a local repository with PSResourceGet.

15 Nov 2026 19 min 7
Error Handling: Terminating and Non-Terminating Errors, $ErrorActionPreference, try/catch and Native Command Exit Codes
DevOps PART 04

Error Handling: Terminating and Non-Terminating Errors, $ErrorActionPreference, try/catch and Native Command Exit Codes

In PowerShell, $ErrorActionPreference = 'Stop' only stops on PowerShell errors; a failing exit code from a native command such as dotnet test also needs $PSNativeCommandUseErrorActionPreference = $true, otherwise publish runs even when tests break and the script exits with 0. We cover the two kinds of errors, try/catch/finally and trap, Write-Error vs throw, stderr and 2>&1, Set-StrictMode, the set -euo pipefail counterparts and a Bookstore build script that stops at the first failure.

15 Nov 2026 16 min 7
Conditions, Loops and Using the Pipeline in Scripts: switch, foreach, Where-Object, ForEach-Object and -Parallel
DevOps PART 03

Conditions, Loops and Using the Pipeline in Scripts: switch, foreach, Where-Object, ForEach-Object and -Parallel

In PowerShell the foreach statement is the fastest on a collection in memory, while for data streaming from a file the pipeline does far less work because it can stop early; a break inside ForEach-Object skips the rest of the script. We show comparison operators, reading logs with switch -Regex, begin/process/end blocks and ForEach-Object -Parallel with a script that checks Bookstore's 200 book covers, along with the $using:, race condition and Format-Table traps.

15 Nov 2026 15 min 8
Variables, Types and Collections: [type] Casts, Arrays, Hashtables, PSCustomObject, Splatting and Strings
DevOps PART 02

Variables, Types and Collections: [type] Casts, Arrays, Hashtables, PSCustomObject, Splatting and Strings

In PowerShell the result of a comparison depends on the type of the value on the left, and Import-Csv reads every column as a string, so data has to be converted to real types up front. Building a publisher report from Bookstore's book CSV, we cover putting $null on the left, arrays and +=, List, hashtables, PSCustomObject, splatting, strings, number and date traps under a Turkish culture, and how a [decimal] cast gives a different result on PowerShell 7.7 because of .NET 11.

15 Nov 2026 18 min 7
Your First PowerShell Script: .ps1, Ways to Run It, #Requires, Comment-Based Help and pwsh vs powershell.exe
DevOps PART 01

Your First PowerShell Script: .ps1, Ways to Run It, #Requires, Comment-Based Help and pwsh vs powershell.exe

Called from inside PowerShell, a script runs in the same process in its own scope; called with pwsh -File, it runs in a new process and reports its result through the exit code, and Write-Error alone does not change that code. With Test-BookstoreHealth.ps1, which checks the Bookstore API, we show &, dot-sourcing, -File vs -Command, the shebang on Linux, #Requires, comment-based help, the differences between Windows PowerShell 5.1 and 7.6 LTS, and the BOM and CRLF traps.

15 Nov 2026 16 min 4
Running Argo CD in Production and What Changed from 2.x to 3.6: SSO, RBAC, Notifications, Metrics and Upgrades
DevOps PART 09

Running Argo CD in Production and What Changed from 2.x to 3.6: SSO, RBAC, Notifications, Metrics and Upgrades

Running Argo CD in production means keeping its own settings in Git, letting people in through SSO with least-privilege RBAC roles and CI with a time-limited token, disabling the admin account, adding notifications and an argocd_app_info alert, and staying within the last three minors. We apply accounts, RBAC and notifications from Git, see the 3.0 update, delete and logs changes, the metrics and the upgrade notes up to 3.6 with real output, and close the series.

15 Nov 2026 13 min 7
Progressive Delivery with Argo Rollouts: Automated Canary Analysis with Prometheus Metrics
DevOps PART 08

Progressive Delivery with Argo Rollouts: Automated Canary Analysis with Prometheus Metrics

Argo Rollouts replaces the Deployment with a Rollout that opens a new version step by step and advances or rolls back by itself based on metrics read from Prometheus. We convert the Bookstore API to a Rollout, set up a canary with 25% and 50% steps in prod, and see with real output a good version going through, a version returning 30% errors aborted in 92 seconds, and Git brought back in line with a revert.

15 Nov 2026 11 min 10
Secrets in GitOps: Sealed Secrets, SOPS and Keeping Secrets Out of Git Entirely
DevOps PART 07

Secrets in GitOps: Sealed Secrets, SOPS and Keeping Secrets Out of Git Entirely

The safe ways to put a secret in Git are to encrypt it so that only the target cluster can open it (Sealed Secrets), to encrypt it with the team's key and decrypt it during manifest generation (SOPS and KSOPS), or to keep only a reference in Git (External Secrets Operator). With real output we take over an existing Secret, hit the strict scope, rehearse losing the key, add KSOPS to Argo CD and compare the three approaches.

15 Nov 2026 12 min 9
Connecting CI to GitOps: Image Tag Promotion, Promoting Environments via Pull Requests and Image Updater
DevOps PART 06

Connecting CI to GitOps: Image Tag Promotion, Promoting Environments via Pull Requests and Image Updater

In GitOps, CI builds the image once, pushes it to a registry and writes which image should run into the config repo as a commit; Argo CD does the deploy. With real output we commit tag and digest to dev from a local CI script, promote to staging and prod via pull requests, hit a conflict between two pipelines writing the same file, watch Argo CD Image Updater drop a digest, and look at the Source Hydrator.

15 Nov 2026 13 min 7
Blog Map