[{"content":"","date":"15 February 2026","externalUrl":null,"permalink":"/categories/","section":"Categories","summary":"","title":"Categories","type":"categories"},{"content":"My whole career in IT, sizing has felt like a dark art. Early on, it was all manual data collection. RVTools exports, Excel spreadsheets, everyone\u0026rsquo;s \u0026ldquo;magic\u0026rdquo; formula that kind of worked but nobody could explain. Over time, those tools got smarter, the spreadsheets standardized, and things got easier.\nSizing Backup Repositories for VBR has been no different, especially now that I\u0026rsquo;m doing VDC Vault designs almost daily. The pattern is always the same. We jump on a Teams call, someone shares their VBR Console, and we start hunting for inputs to plug into the official Veeam Calculator. For small environments, that works fine. For everything else, it\u0026rsquo;s a slog.\nIt\u0026rsquo;s not just sizing anymore. Vault requires specific best practices that aren\u0026rsquo;t always in place. Backups need to be encrypted. Some workloads aren\u0026rsquo;t compatible yet. There are minimum retentions to hit. At scale, the manual audit gets overwhelming. You start making assumptions because you don\u0026rsquo;t have time to click through 200 jobs. Human error creeps in.\nThe data already exists. The Veeam HealthCheck (vHC) collects everything we need: job configs, retention settings, encryption status, all exported as JSON. But there\u0026rsquo;s no quick way to audit that data for Vault readiness, so I built one.\nFair warning: this is an unofficial, work-in-progress tool. It\u0026rsquo;ll catch obvious blockers, but don\u0026rsquo;t bet your migration timeline on it. The validation logic is still being refined, bugs exist, and it\u0026rsquo;s not a replacement for working with your Veeam SE or partner.\nNavigating the Rules # The technical requirements for VDC Vault look straightforward on paper. In practice, they\u0026rsquo;re scattered across multiple help center pages and easy to miss until you\u0026rsquo;re deep in a design session.\nThe blockers I hit most often:\nEncryption is non-negotiable: Everything targeting Vault must be encrypted. If you have unencrypted jobs, you can\u0026rsquo;t just use a \u0026ldquo;Move Backup\u0026rdquo; task to migrate them. You need to set up a Backup Copy Job with encryption enabled instead. 30-day minimum retention: Vault requires a 30-day minimum retention per its product terms. You need to account for this when sizing your Vault capacity, and jobs with shorter retention periods must be adjusted to match this requirement. Workload support: Not everything can go to Vault. Veeam Backup for AWS can\u0026rsquo;t target Vault directly yet, and standalone Agents need to route through a Gateway Server. Then there are the less obvious ones: immutability increasing effective retention (and storage costs), archive tier consuming egress on Foundation edition, Community Edition SOBR limitations. You find these by clicking through job configs in the console, spot-checking retention policies, and hoping you didn\u0026rsquo;t miss something.\nThat\u0026rsquo;s where the Analyzer came from. I got tired of doing this audit manually.\nEnter the Veeam HealthCheck # The good news is that all this data already exists. The Veeam HealthCheck (vHC) is a community-maintained PowerShell script that collects configuration details from your VBR environment and exports them as HTML and JSON reports. It\u0026rsquo;s been around for years and covers everything from job configurations to repository settings to license details.\nThe JSON export is particularly useful because it\u0026rsquo;s machine-readable. Job encryption settings, retention policies, SOBR configurations, workload types—it\u0026rsquo;s all there in a structured format. This makes it perfect for automated analysis.\nAs I\u0026rsquo;ve been building the Analyzer, I\u0026rsquo;ve found gaps in what vHC collects. Some details I need for validation rules weren\u0026rsquo;t being exported, particularly around SOBR capacity tier configurations and archive tier settings. I\u0026rsquo;ve been submitting PRs upstream to add those collection points so the healthcheck data becomes even more complete.\nIf you\u0026rsquo;re not already using vHC in your environment, it\u0026rsquo;s worth adding to your regular maintenance routine. Even without my tool, the HTML report is invaluable for auditing and documentation.\nHow It Works # The goal was to create a \u0026ldquo;pre-flight check\u0026rdquo; that requires zero infrastructure to run. The tool is a client-side web application that ingests a standard Veeam Healthcheck JSON file.\nAll processing happens locally in your browser. No data is uploaded to any external server. Your topology and job details stay on your machine.\nYou export the Healthcheck JSON from your VBR environment, drop it into the landing page, and the tool parses it against a set of validation rules I\u0026rsquo;ve defined based on VDC Vault requirements. Once the scan completes, you get a dashboard showing your readiness status: critical blockers like incompatible versions or unencrypted jobs, and warnings like potential agent configuration issues.\nThe tool doesn\u0026rsquo;t just give you a Pass/Fail. It tries to pinpoint exactly which jobs need attention. For example, the Job Encryption Audit checks every job for encryption status. If it finds unencrypted jobs (which would block a direct migration), it flags them. This tells you immediately that you might need to plan for a SOBR offload or a Backup Copy Job strategy rather than a direct move.\nIt also attempts to aggregate sizing data, helping you estimate the required capacity based on your source data and daily change rates.\nUnder the Hood # I\u0026rsquo;m not a developer, but with AI coding agents these days I can turn tooling ideas into reality. The trick is picking technologies that work well with AI-assisted development and align with practical constraints.\nFor this project, I needed three things: client-side execution (no backend, no security concerns), deployable on Cloudflare\u0026rsquo;s free tier (zero hosting costs), and a stack that AI agents can work with reliably. That led me to:\nCore: React 19.x \u0026amp; TypeScript Build Tool: Vite Styling: Tailwind CSS \u0026amp; shadcn/ui Visualization: Recharts \u0026amp; TanStack Table I\u0026rsquo;m using Test-Driven Development (TDD) to keep the validation logic accurate. This isn\u0026rsquo;t a one-shot AI dump and publish. I go through planning cycles, break down work, have agents write code, then review and fix bugs. TDD gives me confidence that the rules actually work.\nCurrent validation checks:\nCheck Severity Requirement VBR Version Blocker Must be 12.1.2 or higher Job Encryption Blocker All jobs must have encryption enabled (or target encrypted capacity tier) AWS Workloads Blocker Cannot target Vault directly (use Backup Copy Jobs) Capacity Tier Encryption Warning Capacity tier extents must have encryption enabled Capacity Tier Immutability Warning Immutability increases retention (storage cost impact) Capacity Tier Residency Warning Data must remain on capacity tier for 30+ days Retention Period Warning Vault requires a 30-day minimum retention Archive Tier Edition Warning Archive tier consumes egress (consider Advanced edition) Agent Jobs Warning Require Gateway Server or Cloud Connect configuration Global Encryption Warning Best practice to enable globally License Edition Info Community Edition has SOBR limitations The upload page is straightforward - drag and drop your vHC JSON file. The overview dashboard shows your readiness status at a glance, with blockers and warnings listed prominently.\nThe job details page shows every job with its critical attributes - encryption status, workload type, repository target, current size, and daily change rate. The sizing page aggregates this data to help estimate your Vault capacity requirements.\nTry It Out # This is a work in progress. I\u0026rsquo;m battle testing each validation rule before adding more, because I\u0026rsquo;d rather have fewer checks that are accurate than a long list of false positives. Some of the initial rules I threw in just to have something on screen aren\u0026rsquo;t completely accurate yet, and I\u0026rsquo;m refining them as I run more Healthcheck files through the tool.\nA few checks need data that the Healthcheck collector doesn\u0026rsquo;t expose today, particularly around SOBR configurations. I\u0026rsquo;ll be submitting PRs upstream to add those collection points.\nI have a roadmap of features I want to add once the basics are solid, but I\u0026rsquo;m ready to pivot if the community has different priorities. If something is confusing, if a rule is flagging things incorrectly, if the UI doesn\u0026rsquo;t make sense, or if you think there\u0026rsquo;s a check I\u0026rsquo;m missing entirely, I want to know about it. Comment here or open an issue on GitHub.\nTry the VDC Vault Readiness Analyzer comnam90/vdc-vault-readiness Client-side React app that validates Veeam Backup \u0026amp; Replication healthcheck JSON against VDC Vault readiness requirements. TypeScript 0 0 This is a community project, so if you want to dig into the code and submit changes yourself, go for it. I\u0026rsquo;m looking forward to seeing what you all do with it.\n","date":"15 February 2026","externalUrl":null,"permalink":"/2026/02/introducing-the-vdc-vault-readiness-analyzer/","section":"Posts","summary":"I’ve built a client-side tool to help analyze Veeam environments for VDC Vault readiness. It processes Healthcheck JSON files locally to identify blockers like version compatibility, encryption requirements, and workload limitations.","title":"Introducing the VDC Vault Readiness Analyzer","type":"posts"},{"content":"","date":"15 February 2026","externalUrl":null,"permalink":"/posts/","section":"Posts","summary":"","title":"Posts","type":"posts"},{"content":"","date":"15 February 2026","externalUrl":null,"permalink":"/tags/react/","section":"Tags","summary":"","title":"React","type":"tags"},{"content":"","date":"15 February 2026","externalUrl":null,"permalink":"/tags/","section":"Tags","summary":"","title":"Tags","type":"tags"},{"content":"","date":"15 February 2026","externalUrl":null,"permalink":"/tags/tools/","section":"Tags","summary":"","title":"Tools","type":"tags"},{"content":"","date":"15 February 2026","externalUrl":null,"permalink":"/tags/vault/","section":"Tags","summary":"","title":"Vault","type":"tags"},{"content":"","date":"15 February 2026","externalUrl":null,"permalink":"/tags/vdc/","section":"Tags","summary":"","title":"VDC","type":"tags"},{"content":"","date":"15 February 2026","externalUrl":null,"permalink":"/categories/veeam/","section":"Categories","summary":"","title":"Veeam","type":"categories"},{"content":"","date":"15 February 2026","externalUrl":null,"permalink":"/tags/veeam/","section":"Tags","summary":"","title":"Veeam","type":"tags"},{"content":"We\u0026rsquo;ve all been there. You deploy a fresh Veeam Backup \u0026amp; Replication server, everything looks green, and the backups start flying. Then, a few days later, you notice the console is sluggish. Maybe a merge operation takes three times longer than it should, or a SureBackup job times out for no obvious reason.\nYou start investigating, open Task Manager, and spot high CPU usage. Checking the processes, you see Microsoft Defender consuming a large chunk of your resources. Immediately it becomes clear that it\u0026rsquo;s scanning something it shouldn\u0026rsquo;t, so now it\u0026rsquo;s time to check what exclusions you should\u0026rsquo;ve had in place.\nAntivirus software and backup infrastructure don\u0026rsquo;t always get along. Backup tools do exactly what AV is built to stop. They open thousands of files, read them fast, touch huge archives, and push a lot of traffic. When Microsoft Defender decides to real-time scan a 4TB .vbk file every time Veeam touches it, performance doesn\u0026rsquo;t just dip, it falls off a cliff. And of course, Defender finds nothing. It just slows everything down while looking.\nI\u0026rsquo;ve seen brand new VBR servers feel like they\u0026rsquo;ve been built on 10-year-old hardware. Attempts to browse backups freeze and take forever. I\u0026rsquo;ve clicked through the Windows Security UI 57 times (yes, I counted) to manually add every path from Veeam KB1999. It\u0026rsquo;s the list: every process, folder, and file extension to allowlist. Doing it by hand is tedious, error-prone, and a waste of time I\u0026rsquo;d rather spend on actual backup problems.\nSo I built Set-VeeamDefenderExclusions.ps1.\nWhy Another Script? # I didn\u0026rsquo;t want to reinvent the wheel. Before writing anything, I looked at what the community already had. Most existing solutions fall into two main buckets:\nCurrent Scripting Gaps # Solution Type Pros Cons \u0026ldquo;Quick and Dirty\u0026rdquo; Fast to run; simple logic. No idempotency; misses newer components (PostgreSQL) or version-specific paths. \u0026ldquo;Interactive\u0026rdquo; Menus Comprehensive; good for one-off manual work. Bad for automation; can\u0026rsquo;t be used in deployment pipelines or RMM tools because they require user input. I needed something in the middle: fully scriptable, safe to run multiple times, and smart enough to understand a server\u0026rsquo;s role.\nThe Challenge: It\u0026rsquo;s Not Just One List # Veeam infrastructure is modular. A one-size-fits-all exclusion list adds unnecessary noise and reduces security. For example, a dedicated proxy doesn\u0026rsquo;t need exclusions for Enterprise Manager, so why add them? The script needed to understand roles.\nSet-VeeamDefenderExclusions.ps1 # This script is infrastructure-aware. You declare what the server does and it builds the exclusion list accordingly. The full code and documentation are on GitHub:\ncomnam90/vbr-defender-exclusions Automate Microsoft Defender exclusions for Veeam Backup \u0026amp; Replication infrastructure using role-based configuration PowerShell 2 0 1. Role-Based Configuration # You tell the script what the server is, and it builds exclusions dynamically.\n.\\Set-VeeamDefenderExclusions.ps1 -Role BackupServer, BackupInfrastructure Available roles:\nBackupServer: Veeam Backup \u0026amp; Replication Server (catalog folders, configuration database paths) EnterpriseManager: Veeam Backup Enterprise Manager (installation folders, catalog, logs) Console: Veeam Backup \u0026amp; Replication Console (installation folders, temp directories, per-user data) ProtectedGuest: Guest OS of protected Windows VMs (Application-Aware Processing, Guest File System Indexing, SQL Log Backup, Persistent Agent; requires feature flags like -EnableGuestProcessing, -EnableSQLLogBackup) RestoreTarget: Guest OS used as file-level restore target (temporary Veeam VSS support folders) BackupInfrastructure: Proxy, Repository, WAN Accelerator, Mount Server, etc. 2. Intelligent Auto-Detection # Hardcoded paths don\u0026rsquo;t age well. The script queries the registry for the real install paths for the VBR Catalog and NFS Root. It also runs a package detection scan for components like WAN Accelerator or CDP Proxy.\nIf it finds WAN Accelerator, it refuses to continue until you define the cache path. I\u0026rsquo;m not letting you accidentally scan 500GB of dedupe data. It also handles version differences (v12 vs. v13) and correct x86/x64 transport paths.\n3. PostgreSQL Awareness # With PostgreSQL now the default, database exclusions matter. The -IncludePostgreSQL switch finds the version, locates the data directory, and excludes the process path.\n4. Process Scanning # Instead of maintaining a static list of .exe names, the script scans the Veeam installation directories and adds every executable it finds. This makes it resilient against minor updates and new helper tools.\n5. Safety First: Idempotency and WhatIf # Before adding anything, the script checks Get-MpPreference. If an exclusion already exists, it skips it. This keeps logs clean and avoids duplicate entries. It also supports -WhatIf so you can preview changes.\n.\\Set-VeeamDefenderExclusions.ps1 -Role BackupServer -IncludePostgreSQL -WhatIf Requirements # Before running the script, keep these \u0026ldquo;gotchas\u0026rdquo; in mind:\nRun PowerShell as Administrator - The Add-MpPreference cmdlets require elevated permissions. Microsoft Defender must be active - The script uses native Defender cmdlets that require the WinDefend service to be running. Policy-managed environments - If exclusions are managed via GPO, Intune, or Microsoft Defender for Endpoint policies, local changes may fail or revert. Check with your security team if you\u0026rsquo;re unsure. How to Use It # I\u0026rsquo;ve designed the syntax to be simple and flexible depending on your specific deployment needs.\nStandard All-In-One VBR server:\n.\\Set-VeeamDefenderExclusions.ps1 -Role BackupServer -IncludePostgreSQL Repository server:\nThe -IncludeRepositoryExtensions switch adds file type exclusions (.vbk, .vib, etc.) that repositories need but proxies don\u0026rsquo;t. Note that these are global extension exclusions, not scoped to specific folders. For more targeted exclusions, use the -BackupFilesPath parameter to scope exclusions to your repository directories.\n.\\Set-VeeamDefenderExclusions.ps1 -Role BackupInfrastructure -IncludeRepositoryExtensions Undo everything:\nThe -Remove switch reverses the logic. It removes only the Veeam-specific exclusions defined by the roles you specify, leaving other exclusions alone.\n.\\Set-VeeamDefenderExclusions.ps1 -Role BackupServer -Remove You can verify exclusions were added by checking: (Get-MpPreference).ExclusionPath\nMaking It Work # I\u0026rsquo;ve been through enough \u0026ldquo;why is this merge taking 6 hours?\u0026rdquo; moments to know that manual exclusion lists don\u0026rsquo;t scale. You make the list once, miss something, and spend the next three months troubleshooting intermittent slowdowns.\nRun it once during deployment. Run it again after updates. The idempotency means you can safely include it in your deployment automation or post-upgrade runbooks. We trust Veeam to protect our data, so the environment needs to let it do its job.\nIf you hit an edge case I missed, open an issue on GitHub or leave a comment here. I want this to work everywhere.\ncomnam90/vbr-defender-exclusions Automate Microsoft Defender exclusions for Veeam Backup \u0026amp; Replication infrastructure using role-based configuration PowerShell 2 0 ","date":"14 February 2026","externalUrl":null,"permalink":"/2026/02/automating-veeam-defender-exclusions/","section":"Posts","summary":"Manual antivirus exclusions for Veeam infrastructure are tedious and error-prone. This PowerShell script automates the process with role-based detection, PostgreSQL awareness, and idempotent execution.","title":"Automating Veeam Defender Exclusions","type":"posts"},{"content":"","date":"14 February 2026","externalUrl":null,"permalink":"/tags/automation/","section":"Tags","summary":"","title":"Automation","type":"tags"},{"content":"","date":"14 February 2026","externalUrl":null,"permalink":"/tags/backup--replication/","section":"Tags","summary":"","title":"Backup \u0026 Replication","type":"tags"},{"content":"","date":"14 February 2026","externalUrl":null,"permalink":"/tags/microsoft-defender/","section":"Tags","summary":"","title":"Microsoft Defender","type":"tags"},{"content":"","date":"14 February 2026","externalUrl":null,"permalink":"/categories/powershell/","section":"Categories","summary":"","title":"PowerShell","type":"categories"},{"content":"","date":"14 February 2026","externalUrl":null,"permalink":"/tags/powershell/","section":"Tags","summary":"","title":"PowerShell","type":"tags"},{"content":"","date":"11 December 2025","externalUrl":null,"permalink":"/tags/chrome-extension/","section":"Tags","summary":"","title":"Chrome Extension","type":"tags"},{"content":" 🎧 Listen to the AI Deep Dive Your browser does not support the audio element. As a Systems Engineer for Veeam Data Cloud (VDC) Vault, I spend a lot of time running demos. Customers generally like the UI; it is clean and gives high-level numbers at a glance. However, for specific workflows, particularly around billing and chargeback, customers often ask:\n“Is there an API to export this data?”\nWhile the portal is designed to provide excellent operational visibility, strict requirements for external financial modeling or granular chargeback sometimes require raw data access that goes beyond the current UI views.\nTo help customers who need this data immediately for their internal billing workflows, I built a lightweight tool to automate the process.\nWhy Export the Data? # The data is the same, but the motivation for exporting it varies.\nService providers need to map usage to bill their customers or track COGS across tenants. Enterprises need internal chargeback, mapping subscription costs to departments, regions, or environments. Capacity managers need to report on consumption trends so they do not hit subscription limits by surprise.\nIn all of these cases, the requirement is a single CSV that combines vault density, subscription limits, and granular storage usage.\nMeet the VDC Vault Exporter # My solution is the Veeam Data Cloud Vault Exporter.\ncomnam90/veeam-data-cloud-vault-exporter An unofficial community Chrome extension to export usage and configuration data from the Veeam Data Cloud Vault service. JavaScript 1 0 Disclaimer: This is a community project, not official Veeam code. It is provided as-is. I built it as a Chrome extension because it is the lowest-friction option. It runs in the context of your existing browser session. If you are logged into the VDC portal, the extension is too. You do not need to manage API keys or set up an extra OAuth flow.\nThe extension is read-only. It only calls the same endpoints the UI uses to show you usage and subscription data.\nHow It Works # The VDC portal is built on a microservices architecture. The extension reuses the same API calls your browser makes to render the dashboard, but it does the heavy lifting of correlating them.\nSpying on the backend calls using Chrome DevTools I worked this out using Chrome DevTools. By inspecting the Network tab, I realized that the data I wanted wasn\u0026rsquo;t in a single call. The portal fetches tenant details from one service, subscription limits from another, and storage usage from a third.\nThe extension replicates this \u0026ldquo;scatter-gather\u0026rdquo; approach:\n// Function to build API endpoints based on the base URL const buildApiEndpoints = (baseUrl) =\u0026gt; { return { // 1. Get the list of tenants WORKLOAD_TENANTS: (orgId) =\u0026gt; `${baseUrl}/workload-tenants-svc/organizations/${orgId}/workload-tenants?workloadType=VAULT`, // 2. Get the subscription limits (e.g. 50TB vs 500TB) SUBSCRIPTIONS: (orgId) =\u0026gt; `${baseUrl}/subscriptions-svc/organizations/${orgId}/subscriptions`, // 3. Get the actual usage per tenant STORAGE_STATS: (tenantId) =\u0026gt; `${baseUrl}/vault/api/cust-StorageAccount/collectionStorageUsedStatistics?wl_tenant_id=${tenantId}` }; }; A Note on Stability These are internal UI endpoints, so they may change over time as the service evolves. If that happens, the extension will simply stop working until updated. Smart Context and Aggregation # I wanted to ensure the export was context-aware. The extension uses a regex on the active tab URL to figure out where you are. If you are viewing a specific tenant, it exports only that tenant. If you are on the organization dashboard, it exports all relevant tenants.\nBecause the data comes from different services, the extension performs an in-memory join before generating the CSV. It maps the Usage (from the Vault API) and the Limits (from the Subscriptions API) to the correct Tenant (from the Workload API).\nworkloadsData.forEach(tenant =\u0026gt; { const subscription = subscriptionsMap.get(tenant.subscriptionId); // Combine into a single row to avoid VLOOKUPs later const row = [ `\u0026#34;${escapeCSV(tenant.displayName)}\u0026#34;`, `\u0026#34;${escapeCSV(tenant.region)}\u0026#34;`, `\u0026#34;${escapeCSV(subscription?.product.edition || \u0026#39;N/A\u0026#39;)}\u0026#34;`, // ... ].join(\u0026#39;,\u0026#39;); }); The result is a flat, analysis-ready file where every row contains the complete picture for that tenant.\nWith consistent and descriptive column names, the CSV is ready for repeatable analysis in tools like Excel and Power BI.\nRight now the extension targets VDC Vault only. It does not support services like M365, Azure or Entra ID.\nGetting Started # Because this is a community tool, it is not in the Chrome Web Store.\nDownload the source code from the GitHub Releases page. Extract the zip file. In Chrome, go to chrome://extensions and toggle Developer mode. Click Load unpacked and select the extracted folder. Once it is loaded, navigate to your VDC dashboard (either the main view or a specific tenant) and click the extension icon. You can filter by date range (useful for monthly billing cycles) and download your CSV.\nTreat it like any other tool you get from the internet. Only install it from sources you trust, and review the code if you plan to use it in production environments.\nWhat’s Next? # This is just v1. Right now, it solves the immediate problem of exporting Vault data. However, since the VDC portal unifies other services like M365 and Entra ID, there is potential to expand this tool to cover those workloads as well.\nIf you have a specific use case or run into a bug, please open an issue on GitHub. I built this to scratch my own itch, but I would love to hear how it works for you.\nHappy exporting!\ncomnam90/veeam-data-cloud-vault-exporter An unofficial community Chrome extension to export usage and configuration data from the Veeam Data Cloud Vault service. JavaScript 1 0 ","date":"11 December 2025","externalUrl":null,"permalink":"/2025/12/exporting-veeam-data-cloud-vault-data-to-csv/","section":"Posts","summary":"Managing Veeam Data Cloud Vault is great, but sometimes you need raw data. I built a Chrome Extension to export tenant details, subscription limits, and storage usage directly to CSV.","title":"Exporting Veeam Data Cloud Vault Data to CSV","type":"posts"},{"content":"","date":"11 December 2025","externalUrl":null,"permalink":"/tags/vdc-vault/","section":"Tags","summary":"","title":"VDC Vault","type":"tags"},{"content":"","date":"11 December 2025","externalUrl":null,"permalink":"/categories/veeam-data-cloud/","section":"Categories","summary":"","title":"Veeam Data Cloud","type":"categories"},{"content":"","date":"19 March 2025","externalUrl":null,"permalink":"/tags/hardware/","section":"Tags","summary":"","title":"Hardware","type":"tags"},{"content":"","date":"19 March 2025","externalUrl":null,"permalink":"/categories/homelab/","section":"Categories","summary":"","title":"Homelab","type":"categories"},{"content":"","date":"19 March 2025","externalUrl":null,"permalink":"/tags/homelab/","section":"Tags","summary":"","title":"Homelab","type":"tags"},{"content":"","date":"19 March 2025","externalUrl":null,"permalink":"/series/homelab-refresh-2025/","section":"Series","summary":"","title":"Homelab Refresh 2025","type":"series"},{"content":"","date":"19 March 2025","externalUrl":null,"permalink":"/series/","section":"Series","summary":"","title":"Series","type":"series"},{"content":"In Part 1 of this series, I took you on a tour of my current homelab – a real workhorse that\u0026rsquo;s been the backbone for my career growth and side projects for ages. But, let\u0026rsquo;s be honest, technology doesn\u0026rsquo;t stand still, and my workloads were starting to push the old setup to its limits. It was becoming pretty clear to me that an upgrade wasn\u0026rsquo;t just a ‘nice-to-have’ anymore, it was a ‘must-do’. I also walked you through what I was aiming for with this next-gen lab – hitting that sweet spot of performance, being able to scale when needed, keeping the power bill reasonable, and not breaking the bank.\nNow, for the really fun bit! It\u0026rsquo;s time to pick the actual hardware and start piecing this beast together. In this post, I\u0026rsquo;m going to take you behind the scenes of my research, show you the different paths I considered, and reveal the components I finally landed on. And trust me, sometimes the best opportunities jump out when you least expect them!\nSo, let\u0026rsquo;s jump right into this adventure of turning homelab dreams into shiny new hardware reality.\nDiving into the Research # With the decision made to upgrade my homelab and the key goals of performance, scalability, energy efficiency, and cost-effectiveness firmly in mind from Part 1, the next logical step was to dive into the often-complex world of hardware research. My starting point wasn\u0026rsquo;t just Browse for the latest and greatest gear; it was about understanding the specific hardware implications of the software platforms I intended to run and the overall performance I wanted to achieve.\nThis research process involved several key areas: understanding the processor requirements for platforms like Azure Local (Azure Stack HCI), Windows Server 2025, and VMware Cloud Foundation; evaluating storage options to balance speed and efficiency; considering the form factor and expandability of potential server hardware; and navigating the unique challenges of sourcing suitable equipment here in New Zealand.\nProcessor Power: Matching Hardware to Software # My initial focus was on the processors. Each of my target software platforms has its own set of hardware preferences, particularly when it comes to CPU architecture and generation. For Azure Local, Windows Server 2025, and VMware Cloud Foundation, it quickly became apparent that I needed to be looking at either Intel Xeon Scalable (Gen 1 or newer) or AMD EPYC Zen “Naples” chips to ensure compatibility and the necessary processing power. Minimum specifications definitely matter when you\u0026rsquo;re aiming to build a robust and capable lab environment.\nBeyond raw processing power, security is becoming an increasingly critical aspect of both enterprise and even homelab environments. This is where Trusted Platform Modules (TPM) come into play. While TPMs have been around for some time, their role in enhancing system security is becoming more prominent across the board, from consumer devices (like the requirement for Windows 11) to enterprise-grade servers. While often recommended for security features in operating systems like Windows Server and virtualization platforms like ESXi, TPM 2.0 is now a hard requirement for bare metal deployments of Azure Local. This non-negotiable requirement significantly narrowed my hardware search, as I couldn’t simply consider any older server; I had to ensure that any potential candidate either had an integrated TPM 2.0 module or offered the possibility of adding one. This security consideration was a key filter throughout my hardware evaluation process.\nEnterprise-Grade or Bust # Right from the start, I was set on proper server hardware. No desktop PCs pretending to be servers, or those cute but limited mini PCs. Enterprise-grade gear just gives you that rock-solid compatibility with, well, enterprise software, and it\u0026rsquo;s built to be expanded. However, buying brand-new servers? Forget about it. My homelab budget isn\u0026rsquo;t that big! Second-hand market it is.\nStorage Showdown: Flash or Spinning Rust? # SSDs offer dramatically better performance while consuming less power than traditional HDDs From past experience, I knew I was leaning heavily towards an all-flash setup. Why? Well, for starters, the speed boost is just incredible. But also, thinking about power efficiency, flash storage is a winner. I started browsing second-hand SSDs on eBay and was surprised to see that the price gap between SAS-based and NVMe drives had shrunk to almost nothing. NVMe became a no-brainer. Not only would I get insane performance, but it also meant the hardware would be capable of running vSAN\u0026rsquo;s Express Storage Architecture (ESA), which, unlike the Original Storage Architecture (OSA), doesn\u0026rsquo;t require dedicating disks for a separate cache tier, freeing up that capacity for more VMs.\nSpeaking of power, going all-flash would be a game-changer for my energy consumption. My current spinning disks slurp about 7.5W each on average. Sounds small, but across a host, that’s 336W just for storage! NVMe drives like the Samsung PM963? We’re talking 2.5W idle and 7.5W at full tilt. Okay, peak power is similar, but the sheer speed of NVMe (430,000 read and 40,000 write IOPS per drive!) means I need fewer drives overall to get the performance I\u0026rsquo;m after. By aiming for just 4x 1.92TB NVMes per host, I could slash my storage power usage to a measly 10-30W per server. Every watt counts, especially here in NZ where power isn\u0026rsquo;t cheap!\nThe Kiwi Conundrum: New Zealand\u0026rsquo;s Hardware Scene # Now, here’s where living in New Zealand throws a spanner in the works. Being a small country miles away from major tech hubs means our local second-hand market is… limited. TradeMe (that\u0026rsquo;s our local eBay-ish site) has bits and pieces, but finding modern, affordable gear? Like searching for a needle in a haystack. And even when something decent pops up, it\u0026rsquo;s often been stripped bare, coming from small businesses that didn’t spec them up much in the first place.\nTo get real value and find kit that actually met my needs, I had to cast my net wider. eBay in the US became my go-to. Way, way more choice of second-hand enterprise stuff there. Sure, it brings its own headaches – eye-watering shipping costs and import taxes. But the sheer range of options made it worth the pain. It felt like my best shot at striking that balance between getting decent performance without emptying my wallet.\nThe Shortlist: Contenders for the Homelab Crown # After all that digging and market research, I managed to whittle down my options to a shortlist of hardware that looked promising for my upgraded homelab. Each of these had to stack up against my original goals: performance, scalability, being kind to my power bill, and not costing a fortune.\nQuick Comparison Table # Feature Dell PowerEdge R640/R740 (Intel) Dell PowerEdge R7415/R7515 (AMD) Gigabyte/ASUS Barebones Processor Xeon Scalable 1st/2nd Gen EPYC \u0026ldquo;Naples\u0026rdquo;/\u0026ldquo;Rome\u0026rdquo; Various Intel/AMD options Max RAM 768GB with existing DIMMs 512GB with existing DIMMs Varies by model Storage NVMe options available NVMe options available Multiple NVMe slots TPM 2.0 Often Included Often Included Available Power Efficiency Moderate High Varies Parts Availability Excellent Common Limited Relative Cost Moderate-High High Moderate Key Advantage Familiar, well-supported Better perf/watt ratio Customizable Key Disadvantage Higher power usage More expensive, less RAM capacity Potentially harder to source parts Let’s get into the nitty-gritty of each option, shall we?\nOption 1: Sticking with What I Know - Dell PowerEdge 14th Gen Intel (R640 or R740) # Dell hardware is familiar and generally reliable, which is a big plus for me. The 14th generation PowerEdge servers (R640 or R740) represent a solid step up from my current R730xd\u0026rsquo;s, offering compatibility with Intel Xeon Scalable 1st or 2nd Gen processors. The R640s are 1U rack servers that come in various configurations, supporting different drive bay options, including NVMe. For example, listings show configurations with 10 SFF bays and NVMe backplanes. Processor options vary (e.g., Intel Xeon Gold 6138, 6132), as do RAM configurations (e.g., 16GB, 64GB, 128GB), though the R640 supports up to 1.5TB of RAM. However, for me, the practical RAM capacity depends on the number of DIMM slots, as I plan to use my existing 32GB DDR4 DIMMs. The R640s and R740s come with 24 DIMM slots which would give me 768GB. Storage controllers also vary (e.g., HBA330, H730P), and networking can range from 1GbE to 10GbE SFP+. While TPM 2.0 is possible, it\u0026rsquo;s not always included; for example, it was present in a VXRAIL E560F (which uses the R640 chassis) but not in other R640 listings. The R740s by comparison are more of less the same but are 2U Servers, generally meaning more drive bays, more PCIe slots, and better cooling. My main hesitation with these Intel-based servers remains their relatively higher power consumption. Option 2: AMD Enters the Ring – Dell PowerEdge 14th or 15th Gen AMDs (R7415 or R7515) # Staying in the Dell family, I also checked out their AMD-powered servers. These had some instant appeal because of their single-processor design, making the most of AMD\u0026rsquo;s higher core counts. Like the Intel Dells, they’ve got TPM 2.0, DDR4 support, and NVMe storage options. AMD’s reputation for performance-per-watt, especially with single-CPU setups, is strong – meaning potentially better power efficiency. However, these AMD servers tend to be pricier on the second-hand market. Probably because they\u0026rsquo;re a bit rarer than the Intel versions and are hot property for labs. Also, that single CPU design limits them to 16 DIMM slots – maxing out at 512GB RAM with my 32GB sticks, compared to the 24 slots and 768GB in the Intel models. Everything comes with a trade off.\nOption 3: Going Barebones DIY – Gigabyte or ASUS # Then I thought, “Why not go full DIY?” Gigabyte and ASUS were brands I knew well from my PC-building days, and they both have a good name for server-grade gear. Fellow MVP Philip Elder has built server solutions using them, which gave me confidence. These barebones systems offer both Intel and AMD options, and plenty of NVMe slots. Sounded good on paper, but they’re less common in the second-hand world, which worries me about finding spares down the line. Especially when it comes to TPM 2.0, as usual the eBay listing are unclear on whether they\u0026rsquo;re included. And honestly, the cost savings weren’t massive enough to justify the potential hassle of sourcing replacement parts if something went wrong.\nWeighing it All Up # Truthfully, I was leaning towards the Dell R640s or R740s. Mainly because they are just everywhere. That means future upgrades and fixes would be easier. Dell parts and Intel CPU upgrades of that generation are much easier to get hold of. Plus, sticking with Intel meant if I did upgrade to 2nd Gen processors later, I could potentially play with Intel Optane Memory DIMMs and boost my RAM beyond 768GB without emptying my wallet on new regular DIMMs.\nThe Unexpected Twist – Jackpot # Just when I thought I was all set on the Dell 14th Gen Intels! A local opportunity popped up that was just too good to ignore.\nMy newly acquired ex-NetApp SolidFire (QCT) servers Out of the blue, a listing appeared on TradeMe for a bunch of 1U servers. These weren\u0026rsquo;t just any servers – they were packing Intel 1st Gen Scalable processors, a healthy chunk of RAM, NVMe drives, and a mix of 1GbE and 10GbE NICs. Now they didn\u0026rsquo;t match my original plan for 4x 1.92TB disks per server, but with 12 U.2 Slots I\u0026rsquo;ve plenty of room to expand in future. Turns out, they were ex-NetApp Solidfire nodes, actually rebranded QCT QuantaGrid servers. Now, QCT hardware, while used by the big guys (hyperscalers and OEMs), isn\u0026rsquo;t something you see sold to regular folks every day. That was a bit of a risk – spare parts might be harder to find. And since they were running custom NetApp software, future firmware updates could be a headache. But… the price. It was just crazy good. And the hardware ticked all the boxes. So, I took the plunge and managed to snag three of these servers for just $900NZD each! Seriously!\nComponent Specification Maximum Capacity Model QCT QuantaGrid D52B-1U Processors 2x Intel Xeon Gold 5120 (14C/28T @ 2.2GHz) 2x Intel Xeon Scalable 1st/2nd Gen (up to 205W TDP) Memory 256GB DDR4 (8x 32GB DIMMs) 24x DIMM slots (potentially up to 3TB with 128GB LRDIMMs) Storage 2x Samsung PM963 1.92TB NVMe Up to 12x 2.5\u0026quot; NVMe SSDs 1x 128GB SATADOM Up to 2x 256GB SATADOM Networking 2x 1GbE, 2x 10GbE 1x OCP 2.0 NIC up to Dual 25GbE, 3x PCIe NICs up to Dual 100GbE Future-proofing is key for me, especially for Azure Local and S2D, so RDMA was a must. These servers had an OCP 2.0 slot with 1GbE NICs, which were ripe for upgrading to 10GbE+. Checking the QCT site, they listed compatibility with Mellanox adapters. Perfect! I ordered a ConnectX-4 LX 25GbE card for each server. These are even better than my old ConnectX-3 Pros – less power, faster speeds, tons of offload features, and they play nicely with pretty much any OS. And as for the TPM 2.0 modules, I grabbed 4 from eBay UK even though I only got 3 server, just in case of future failures or wanting to expand.\nSo, the final score? Three servers that are every bit as capable as those Dell R640s I was eyeing, but for half the price, and sourced right here in NZ. They meet all my boxes for modern OS compatibility, are cost-effective, and have room to grow.\nHardware: sorted. Now, the real fun begins – building it all out and putting it through its paces!\nBuilding the Homelab: From Battered Boxes to the Rack # So, those three QCT servers finally shipped out from Wellington, heading south to Christchurch. Except, the courier decided to take them on a bit of a South Island tour, with an unexpected stop in Cromwell before finally making their way back to me in Christchurch. It was a logistical adventure, to say the least!\nThe bizarre shipping route my servers took across the South Island When the servers finally arrived, the state of the boxes was concerning. They looked like they\u0026rsquo;d had a very rough trip, with dents and tears aplenty. And unfortunately, the servers inside hadn\u0026rsquo;t fared much better. The chassis of one was noticeably bent, requiring some careful bending to get it (mostly) straight and ready for the rack. The third server arrived a few days later in similar condition.\nThe servers arrived with significant shipping damage, including bent chassis and torn packaging With the servers finally wrestled out of their packaging, the next step was getting them into the rack. Despite the slight bend in one of the chassis, I managed to slide all three into place. It\u0026rsquo;s always a satisfying feeling to see the physical hardware taking shape.\nThe three QCT servers finally installed in the rack, ready for configuration As I started inspecting the hardware, I had a pleasant surprise. It turned out that the PCIe NICs in all three servers were actually 25GbE Mellanox ConnectX-4 LX adapters! This was fantastic news as it meant I already had high-speed networking capabilities beyond the onboard 1GbE ports. It seems my purchase of separate OCP 25GbE NICs might have been unnecessary had the original listing been more detailed, but having extra 25GbE adapters isn\u0026rsquo;t the worst problem to have!\nComparing the original 1GbE OCP NIC (left) with the new 25GbE Mellanox ConnectX-4 LX adapter (right) I purchased as upgrades Existing Network Infrastructure # While the compute and storage are getting a significant overhaul, the core of my network infrastructure is already well-equipped to handle the demands of the upgraded homelab. I\u0026rsquo;ll be keeping my existing pair of Dell S4048-ON 10GbE Top of Rack switches. These switches are absolute workhorses, providing all the high-performance connectivity I need and boasting impressive Layer 3 routing capabilities. This will be crucial for when I start diving into more advanced networking concepts like VMware NSX or Microsoft\u0026rsquo;s SDN Stack.\nFor out-of-band management and lower-bandwidth connections, I\u0026rsquo;ll continue to rely on my Unifi 1GbE Out-of-Band switch. It\u0026rsquo;s been rock solid for managing all my 1GbE connections and keeps the management plane separate from the high-performance data network.\nFinally, to ensure proper security and segmentation between my homelab environment and the rest of my home network, my Fortigate Firewall remains in place. It\u0026rsquo;s more than capable of handling the traffic and providing the necessary security policies.\nSo, while the servers are getting a major boost, the networking foundation is already robust and ready to support the increased performance and complexity I\u0026rsquo;m planning for in the lab. A full network overhaul isn\u0026rsquo;t necessary at this stage, allowing me to focus my current efforts and budget on the compute and storage upgrades.\nFrom Parts to Platform: The Next Phase Awaits # So, that brings us to the end of Part 2. We\u0026rsquo;ve explored the options, made the tough decisions, and even wrestled some slightly battered servers into the rack. The foundation for the new homelab is now physically in place, and I\u0026rsquo;m excited about the potential it holds.\nIn Part 3, we\u0026rsquo;ll finally power up this new hardware and see what it can really do. I\u0026rsquo;ll be taking you through the initial steps of getting the system operational, putting it through its paces with some revealing performance tests, and sharing my thoughts on what the future holds for this upgraded homelab. Stay tuned – the real fun is just about to begin!\n","date":"19 March 2025","externalUrl":null,"permalink":"/2025/03/upgrading-my-homelab-choosing-and-building-the-right-hardware/","section":"Posts","summary":"Time to pick hardware! After researching Dell R640/R740, AMD EPYC servers, and barebones options, an unexpected find on TradeMe changed everything—three ex-NetApp SolidFire servers for just $900 NZD each!","title":"Upgrading My Homelab: Choosing and Building the Right Hardware","type":"posts"},{"content":"When it comes to personal IT infrastructure, few things are as rewarding as a well-optimized homelab. Whether you use it for testing, development, or just staying hands-on with technology, your homelab is a dynamic reflection of your needs and ambitions. However, as workloads evolve and requirements grow, the time inevitably comes to upgrade. For me, that time is now.\nIn this first post of a three-part series, I\u0026rsquo;ll walk you through my homelab\u0026rsquo;s current setup, the challenges I\u0026rsquo;m facing, and the goals and requirements shaping my upgrade plans.\nWhy a Homelab? # For me, a homelab is much more than a set of servers and networking gear—it’s a cornerstone of my professional growth and a space to innovate. It has allowed me to:\nExplore New Technologies: From virtualization to software-defined networking, my homelab has given me the freedom to experiment without risk. For example, I’ve been able to deep-dive into VMware Cloud Foundation, Azure Local, and hybrid cloud tools like Azure Arc-enabled servers. Build Practical Skills: Staying hands-on is critical in IT, and my homelab ensures I can practice troubleshooting, deploying, and optimizing systems. For instance, setting up data protection systems like Veeam has honed my expertise in backup and recovery. Test Real-World Scenarios: I’ve used my lab to replicate client environments and validate proof-of-concept solutions. This has not only saved time but also improved confidence in implementations. Support Personal Projects: Beyond professional benefits, my homelab supports my hobbies, from hosting media servers to automating my home network. These benefits aren’t unique to me—anyone in IT can use a homelab to experiment, learn, and grow. Whether you’re looking to advance your career or solve unique challenges, a homelab is an invaluable resource.\nMoving on from this, let’s take a closer look at the specifics of my current setup and the limitations that are driving the need for an upgrade.\nCurrent Homelab Overview # My existing homelab has served me well for the past 5 years. It includes:\nHardware # Fortigate Fortinet 100D Firewall Ubiquiti Unifi 24-Port Switch (US-24-G1) for out-of-band connections and single uplink devices 2x Dell S4048-ON 10GbE 48-Port Top-of-rack switches 4x Dell PowerEdge R730xd Servers 2x Intel Xeon E5-2650v4 12C/24T @ 2.20GHz Procs 16x 32GB (512GB) DDR4 ECC RDIMMs 2x 200GB Intel S3600 SATA SSD OS Disks 4x 800GB Intel S3710 SATA SSD Cache Disks 8x 4TB 7,200 RPM SATA HDDs Dual Port Intel i350 1GbE NIC Dual Port Intel x520 10GbE NIC Dual Port Mellanox ConnectX-3 Pro 10GbE NIC Dell Optiplex 7060 Micro PC Intel i7-8700T 6C/12T @ 2.40GHz Proc 2x 32GB (64GB) DDR4 SODIMMs 1TB M.2 NVMe Disk Single port Intel I219-LM 1GbE NIC QNAP TSV-1271U-RP 12 Bay 2U NAS with 12x 6TB SATA HDDs Software # Primarily virtualisation solutions, initially Windows Server Hyper-V with Storage Spaces Direct, then Azure Stack HCI and more recently VMware Cloud Foundation (VCF). Data Protection systems such as Veeam Backup \u0026amp; Replication, Veeam Enterprise Manager, Veeam One, Veeam Service Provider Console, Veeam Cloud Connect and Veeam Recovery Orcestrator. SDN solutions like NSX and Microsoft SDN Aria Suite solutions for VCF; Aria Operations, Aria Operations for Logs, Aria Operations for Networks and Aria Automation Hybrid Cloud tooling like Azure Arc-enabled Servers, Azure Arc-enabled VMware vSphere, Azure Arc-enabled Kubernetes and more. Storage solutions like Dell Data Domain (DDVE) and Minio Challenges # High power consumption and increasing maintenance requirements. The Dell PowerEdge R730xd servers use about 300W each, their 4TB HDDs are 8-9 years old and with so many of them, replacements are costly. Insufficient performance and capabilities for newer technologies. Nested labs are challenging due to poor performance, and the time required to deploy new workloads hinders motivation and reduces productive lab time. Addressing this with more performant hardware is critical. Limited scalability to accommodate future needs. These servers can\u0026rsquo;t support newer CPUs, NVMe drives without adapters, and finding more of them in New Zealand is a challenge. A scalable and modular setup is essential for future-proofing. Below is a diagram of my current homelab setup for a visual representation of its components and layout.\nWhile this setup has been reliable, it’s clear that I’ve hit its limits. Tasks that were once manageable now feel constrained, prompting the need for an upgrade. So let\u0026rsquo;s look at the next step of defining what I hope to achieve with this upgrade.\nGoals for the Homelab Upgrade # Before diving into hardware options, I’ve taken time to define clear goals for the upgrade:\nEnhanced Performance and compatability Support more demanding workloads, such as nested labs and kubernetes. Compatability with Azure Local Bare Metal(such as TPM 2.0 modules) Reduce performance barriers to spend less time waiting for applications to deploy and patch. Scalability and Flexibility Add capacity for future growth without overhauling the entire system. Embrace modularity for easier upgrades and reconfiguration. Energy Efficiency Reduce power consumption to lower operating costs. Robustness and Reliability Incorporate redundancy and fault tolerance to minimize downtime. Cost-Effectiveness Strike a balance between upfront investment and long-term value. Requirements for the New Setup # To achieve these goals, I’ve outlined specific requirements for my new homelab:\nHardware At least Intel Xeon Scalable /AMD EPYC Gen 1 or newer and 16 cores per host. 512GB RAM per host, ideally compatible with DDR4 so that I can re-use existing parts. All-flash storage, either SSD or ideally NVMe. Energy-efficient components. TPM 2.0 modules to support hardware security features RDMA-capable Network Cards, at least 2 ports 25GbE. Minimum 3 hosts. Software Compatibility with Azure Local and VCF 5.2 Looking Ahead # With these goals and requirements in mind, the next step is to evaluate potential hardware options. In the second post of this series, I’ll dive into the research process, share the components I considered, and reveal the final hardware I chose to power my upgraded homelab.\nUpgrading a homelab is always an exciting journey, and I’m thrilled to share mine with you. Whether you’re planning your own upgrade or simply curious about what goes into modernizing a homelab, I hope this series provides insight and inspiration.\nStay tuned for Part 2: Choosing and Building the Right Hardware!\nUpdated 2025-03-19: Added link to Part 2\n","date":"22 January 2025","externalUrl":null,"permalink":"/2025/01/upgrading-my-homelab-planning-for-the-future/","section":"Posts","summary":"My Dell R730xd servers have served well, but power consumption, aging drives, and limited scalability mean it’s time for an upgrade. Part 1 covers my current setup, challenges, and the goals shaping my new homelab.","title":"Upgrading My Homelab: Planning for the Future","type":"posts"},{"content":"","date":"20 August 2024","externalUrl":null,"permalink":"/tags/epoch/","section":"Tags","summary":"","title":"Epoch","type":"tags"},{"content":"If you\u0026rsquo;ve ever dealt with Unix Epoch time in PowerShell, you know it can be a hassle. By default, Get-Date doesn’t output or accept Epoch time, forcing users to manually calculate the seconds between 1970 and their target date.\nPS C:\\\u0026gt; # Examples of Previous ways to calculate current Unix Time PS C:\\\u0026gt; [int][double]::Parse((Get-Date -UFormat %s)) 1724142672 PS C:\\\u0026gt; [System.Math]::Truncate((Get-Date -UFormat %s)) 1724142720 Fortunately, there’s a better way. The .NET DateTimeOffset class provides an efficient method to handle Unix Epoch timestamps directly in PowerShell.\nPS C:\\\u0026gt; $Date = Get-Date PS C:\\\u0026gt; [System.DateTimeOffset]::new($Date) DateTime : 20/08/2024 7:54:59 PM UtcDateTime : 20/08/2024 7:54:59 AM LocalDateTime : 20/08/2024 7:54:59 PM Date : 20/08/2024 12:00:00 AM Day : 20 DayOfWeek : Tuesday DayOfYear : 233 Hour : 19 Millisecond : 287 Microsecond : 557 Nanosecond : 0 Minute : 54 Month : 8 Offset : 12:00:00 TotalOffsetMinutes : 720 Second : 59 Ticks : 638597804992875570 UtcTicks : 638597372992875570 TimeOfDay : 19:54:59.2875570 Year : 2024 While the output doesn’t display Unix Time by default, the DateTimeOffset object includes methods to convert to Unix Time in either seconds or milliseconds, depending on your accuracy needs.\nFor example, to get the current time in Unix Epoch seconds:\nPS C:\\\u0026gt; [System.DateTimeOffset]::new( (Get-Date) ).ToUnixTimeSeconds() 1724140499 Get-Date can be swapped out for any other PowerShell DateTime object to convert an existing timestamp.\nConverting from an existing Unix timestamp is even easier. The DateTimeOffset class has a FromUnixTimeSeconds method, allowing you to convert back to a human-readable date and time object.\nFor instance, converting the Unix time from the previous example back to a readable format:\nPS C:\\\u0026gt; $UnixTimestamp = \u0026#34;1724140499\u0026#34; PS C:\\\u0026gt; [DateTimeOffset]::FromUnixTimeSeconds($UnixTimestamp) DateTime : 20/08/2024 7:54:59 AM UtcDateTime : 20/08/2024 7:54:59 AM LocalDateTime : 20/08/2024 7:54:59 PM Date : 20/08/2024 12:00:00 AM Day : 20 DayOfWeek : Tuesday DayOfYear : 233 Hour : 7 Millisecond : 0 Microsecond : 0 Nanosecond : 0 Minute : 54 Month : 8 Offset : 00:00:00 TotalOffsetMinutes : 0 Second : 59 Ticks : 638597372990000000 UtcTicks : 638597372990000000 TimeOfDay : 07:54:59 Year : 2024 Short and to the point, but I hope this helps next time you\u0026rsquo;re working with Unix Epoch timestamps in PowerShell!\n","date":"20 August 2024","externalUrl":null,"permalink":"/2024/08/simplifying-unix-epoch-timestamps-in-powershell-using-datetimeoffset/","section":"Posts","summary":"Stop manually calculating seconds since 1970! The .NET DateTimeOffset class makes Unix Epoch conversions simple with ToUnixTimeSeconds() and FromUnixTimeSeconds() methods.","title":"Simplifying Unix Epoch Timestamps in PowerShell Using DateTimeOffset","type":"posts"},{"content":"","date":"20 August 2024","externalUrl":null,"permalink":"/tags/unix/","section":"Tags","summary":"","title":"Unix","type":"tags"},{"content":"","date":"6 August 2024","externalUrl":null,"permalink":"/tags/backup/","section":"Tags","summary":"","title":"Backup","type":"tags"},{"content":"","date":"6 August 2024","externalUrl":null,"permalink":"/tags/vbr/","section":"Tags","summary":"","title":"VBR","type":"tags"},{"content":" Introduction # In today\u0026rsquo;s fast-paced IT environment, maintaining up-to-date backups is crucial for data protection and disaster recovery. Veeam Quick Backup functionality offers a streamlined solution for efficiently backing up individual VMs or groups of VMs. This feature is designed to be quick and user-friendly, making it an excellent tool for system administrators who need to perform ad-hoc backups without disrupting their regular backup schedules.\nIn this blog post, we’ll delve into the Quick Backup feature, focusing on how to leverage it using PowerShell. This powerful combination allows for automation and customization, enabling you to integrate Quick Backup into your existing workflows seamlessly. Whether you\u0026rsquo;re looking to protect critical data before performing updates or need a quick safety net during system maintenance, Veeam Quick Backup with PowerShell provides the flexibility and control you need.\nLet’s explore how to set up and use Veeam Quick Backup with PowerShell, ensuring your data remains secure with minimal effort.\nWhy Use Quick Backups? # Quick backups enable you to run ad-hoc backups of one or more VMs without running the entire backup job they are part of. This can be particularly useful for backing up a machine before patching, making a major change, or restoring a previous recovery point.\nYou might be thinking, \u0026ldquo;But I can just use a VM snapshot for that!\u0026rdquo; Unlike VM snapshots, quick backups are application-aware1, providing a more reliable recovery point. Additionally, quick backups can help keep a VM updated in preparation for leveraging Veeam\u0026rsquo;s Instant Recovery capabilities, such as migrating to another platform, like moving from VMware to Hyper-V.\nPrerequisites # To perform a quick backup, the following requirements must be met:\nA backup job processing the VM exists on the backup server. A full backup file for the VM exists in the backup repository configured in the backup infrastructure. NOTE: You cannot perform a quick backup for VMware Cloud Director VMs processed with VMware Cloud Director jobs2. Attempting this will result in an error in both the UI and PowerShell:\nError in PowerShell:\nStart-VBRQuickBackup : Failed to perform quick backup for VM TestVM01-LFuO. Reason: VM is not added to any job or full backup not found At line:1 char:1\n+ Start-VBRQuickBackup -VM $VM -Verbose\n+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n+ CategoryInfo : InvalidOperation: (:) [Start-VBRQuickBackup], Exception\n+ FullyQualifiedErrorId : QuickBackupErrorId,Veeam.Backup.PowerShell.Cmdlets.StartVBRQuickBackup\nGetting started # Now that we\u0026rsquo;ve established why you might want to use quick backups and what you need to get started, let’s dive in.\nFirst, select the VM or VMs you want to back up using Find-VBRViEntity for VMware VMs or Find-VBRHvEntity for Hyper-V VMs.\n# Single VM called TestVM01 $VMs = Find-VBRViEntity -Name TestVM01 # Add an additional VM called DC01 $VMs += Find-VBRViEntity -Name DC01 # Or Select all VMs starting with DC0 $VMs = Find-VBRViEntity -Name DC0* Next, kick off Start-VBRQuickBackup and pass it the VMs you want to back up.\n# Start a quick backup job Start-VBRQuickBackup -VM $VMs # Start a quick backup job but wait for it finish Start-VBRQuickBackup -VM $VMs -Wait It’s as easy as that! The -Wait switch is useful if you\u0026rsquo;re using this as part of a script and don\u0026rsquo;t want to proceed to the next step, such as installing Windows Updates, until the backup is complete.\nDemo # Here’s a quick backup in action. Feel free to pause and copy/paste the commands right from the recording!\nWhat about retention # Now that you’ve created your backups, how do they fit into your retention policy, and when will they be removed?\nWhen you perform a quick backup, it creates a single VM incremental restore point. Unlike a regular backup that contains data for all VMs in a job, a single VM incremental restore point contains data only for a specific VM.\nA single VM restore point is not considered a full-fledged restore point in the backup chain. From the retention policy perspective, a single VM restore point is grouped with a regular restore point following it. When Veeam needs to delete a single VM restore point by retention, it waits for the next regular restore point to expire, effectively increasing the retention by one restore point for some time. After the next regular restore point expires, Veeam will clean up two restore points at once.\nFor example, if you have a backup job that runs at 3 AM, with a 3-day retention and a synthetic full backup every Sunday and Wednesday:\nOn Tuesday, you need to apply some patches to a server, so you perform a quick backup at 5 PM. This backup will be grouped with the next regular backup, which will be the Wednesday full backup, and will expire on Sunday instead of Saturday, along with the regular incremental from Tuesday.\nSunday Monday Tuesday Wednesday Thursday Friday Saturday Full Backup Incremental Backup Incremental Backup Full Backup Incremental Backup Incremental Backup Incremental Backup .VBK .VIB .VIB .VBK .VIB .VIB .VIB Expires Thursday Expires Friday Expires Saturday Expires Sunday Expires Monday Expires Tuesday Expires Wednesday Quick Backup .VIB Expires Sunday Wrapping up # Well, there you have it—quick backups using PowerShell. Hopefully, this has shown just how easy it can be to include ad-hoc backups into your workflows, so you don’t have to rely solely on VM snapshots.\nFor more information, I recommend visiting the Veeam Help Center for the latest updates.\nQuick Backup jobs inherit the settings of their parent backup jobs, including all application-aware and file indexing settings.\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nIf you process a VMware Cloud Director VM with a regular backup job, you can switch to the Computer view and start the quick backup operation for this VM.\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n","date":"6 August 2024","externalUrl":null,"permalink":"/2024/08/veeam-quick-backup-with-powershell/","section":"Posts","summary":"Need a quick backup before patching or making changes? Veeam Quick Backup creates ad-hoc, application-aware backups of individual VMs. Here’s how to use it with PowerShell—it’s just two commands!","title":"Veeam Quick Backup with PowerShell","type":"posts"},{"content":"","date":"7 April 2024","externalUrl":null,"permalink":"/tags/c2-object-storage/","section":"Tags","summary":"","title":"C2 Object Storage","type":"tags"},{"content":"","date":"7 April 2024","externalUrl":null,"permalink":"/tags/object-storage/","section":"Tags","summary":"","title":"Object Storage","type":"tags"},{"content":"In this article, I delve deeper into affordable object storage by exploring the configuration of Synology\u0026rsquo;s CloudSync app on a Synology NAS for data backup to the Synology C2 Object Storage service. To follow along, you can easily sign up for a 15GB trial account.\nSetting Up a C2 Object Storage Bucket # Let\u0026rsquo;s kick off by establishing the Object Storage bucket. We\u0026rsquo;ll log in to the C2 website, where the URL for the APAC region is https://object.tw.c2.synology.com/bucket. The user interface is straightforward. For first-time users like me, clicking the Create Bucket button initiates the process. I\u0026rsquo;ll name my bucket based on the device and app utilizing it, such as NAS01-CloudSync. Simultaneously, I\u0026rsquo;ll generate an access key, crucial for configuring Synology CloudSync. Next, we can customize data protection settings. Opting for versioning ensures copies of altered data (e.g., edited photos) are retained, while object lock prevents modifications or deletions within a specified timeframe post-upload. I opt to enable versioning for future data synchronization. Finally, we receive the access key and secret key necessary for bucket connection. Let\u0026rsquo;s download them promptly for later use. Setting Up CloudSync # To initiate the process, ensure the CloudSync app is installed on your NAS via the Package Center. Once installed, open CloudSync and proceed to add a new connection to a Cloud Provider. For this setup, I\u0026rsquo;m configuring a connection to Synology C2 Object Storage, where the previously created bucket resides. Since this is an integrated solution, there\u0026rsquo;s no need for URLs or endpoint details. Simply provide the Access Key and Secret Key obtained earlier to automatically discover the bucket. Next, create the first sync task for this cloud provider. In my case, I\u0026rsquo;m syncing up my local folder of Photos from New Zealand. While the default sync direction is bidirectional, I can adjust it as needed. Optionally, you can enable encryption for added security. However, if accessibility across different object storage applications is essential, you may choose to leave this feature disabled. Once configured, monitor the upload process from the CloudSync app as it seamlessly uploads all your photos to the designated bucket. Retrieving Previous Versions # Now that my photos are safely stored in C2 Object Storage, I encountered a common dilemma: accidentally overwriting the original copy of a photo during editing. Fortunately, since we enabled bucket versioning upon creation, let\u0026rsquo;s explore how to access and recover those previous versions.\nFirst, navigate back to the C2 Object Storage web interface, and locate your file within the designated bucket and folder. For instance, mine is in the temp folder at the root of the bucket. By enabling the Show versions option, you can easily identify files with previous versions, their respective space consumption, and the number of stored versions. Hover over the file and access the menu to view all available versions. From here, select the original version of the file and download it using your browser. While there\u0026rsquo;s currently no native integration with the CloudSync app or Synology NAS to directly recover previous versions from Object Storage, you can still download and copy it back onto your NAS. Even after deletion, previous versions persist, offering a safety net for accidental deletions. Simply follow the same process to recover them. Alternatively, you can permanently delete all versions from the C2 Object Storage web interface. Exploring C2 Object Storage with Cyberduck # An added benefit of utilizing CloudSync with Object Storage is the ability to access your bucket data using third-party applications, even when unable to access the original NAS. To demonstrate this capability, let\u0026rsquo;s use Cyberduck to connect to the bucket and view the previously restored photo. In Cyberduck, initiate a new connection and select Amazon S3 as the connection type. {:height 496, :width 749} Utilize the Access Key ID and Secret Key obtained from the CloudSync app connection. However, since we\u0026rsquo;re using C2 Object Storage instead of Amazon S3 Storage, adjust the Server address accordingly. Copy the endpoint details from the C2 Object Storage UI on the buckets screen. Paste the endpoint into the Server field in Cyberduck. Beware of a potential bug where the connection type may switch to WEBDAV instead of Amazon S3. This occurs due to the copied endpoint server address starting with https://. To resolve this, paste the endpoint into a text editor and remove the https:// prefix before inputting it into Cyberduck. With the connection established, navigate to your bucket, locate the desired photo, and preview it directly on your computer. Conclusion: Wrapping Up # I trust that this journey through Synology CloudSync and C2 Object Storage proves beneficial for others seeking to fortify their data protection measures. It presents a straightforward method to initiate the transfer of essential data offsite, shielding it from potential failures or corruption.\n","date":"7 April 2024","externalUrl":null,"permalink":"/2024/04/safeguarding-synology-data-with-cloudsync-and-c2-object-storage/","section":"Posts","summary":"A complete guide to backing up Synology NAS data to C2 Object Storage using CloudSync. Covers bucket setup, sync configuration, version recovery, and accessing your data with Cyberduck.","title":"Safeguarding Synology Data with CloudSync and C2 Object Storage","type":"posts"},{"content":"","date":"7 April 2024","externalUrl":null,"permalink":"/categories/synology/","section":"Categories","summary":"","title":"Synology","type":"categories"},{"content":"","date":"7 April 2024","externalUrl":null,"permalink":"/tags/synology/","section":"Tags","summary":"","title":"Synology","type":"tags"},{"content":"","date":"7 April 2024","externalUrl":null,"permalink":"/tags/synology-cloudsync/","section":"Tags","summary":"","title":"Synology CloudSync","type":"tags"},{"content":"With Synology\u0026rsquo;s C2 Object Storage, the company continues its tradition of delivering a solution that strikes the perfect balance between simplicity and cost-effectiveness in a dynamic market.\nHaving relied personally on Synology NAS devices for over a decade, I\u0026rsquo;ve consistently experienced their impressive capabilities. These devices embody a set-and-forget ethos, providing seamless updates throughout their lifespan and never experiencing a failure outside of normal HDD issues. Their inherent simplicity ensures that, unlike the IT challenges I have to navigate at work, managing storage at home is a hassle-free experience.\nSynology C2 Object Storage mirrors this user-friendly approach, presenting an S3-compatible Object Storage solution that precisely caters to your needs without unnecessary complexities. Right from the start, its pricing strategy sets it apart from major public cloud providers. Unlike the intricate calculations often required with other providers, Synology simplifies the process with a flat $6.99/month per TB fee. This inclusive pricing covers not only raw storage costs but also eliminates concerns about additional egress fees, as it encompasses total monthly egress equal to the purchased storage capacity.\nFor my specific use case, focusing on data protection, this pricing model proves exceptional. It ensures that retrieving data from the Object Storage offering doesn\u0026rsquo;t incur unexpected costs. Even in scenarios where a comprehensive recovery of the entire stored dataset is necessary, the flat monthly fee remains constant. This means I can perform data recoveries without hesitation, knowing that the transparent pricing structure aligns seamlessly with my data protection requirements.\nSynology has another storage offering tailored specifically for safeguarding data on their NAS devices—C2 Storage. Following the same all-inclusive pricing as their object storage counterpart, C2 Storage introduces additional features like backup data deduplication, version control, and cross-device syncing for users with multiple NAS devices. Confirming backups with C2 Storage is conveniently done through the HyperBackup application, while C2 Object Storage users rely on the CloudSync app for the same purpose.\nYou might be wondering why opt for C2 Object Storage when there\u0026rsquo;s a native solution like C2 Storage designed explicitly for securing NAS data. The answer lies in the flexibility provided by C2 Object Storage. Unlike C2 Storage, exclusively catering to Synology NAS backups, C2 Object Storage functions as a versatile S3-compliant service. Whether hosting website photos or implementing a third-party backup solution (check out Ben Young\u0026rsquo;s post on Veeam integration), C2 Object Storage emerges as a cost-effective choice with diverse applications.\nWhile Synology\u0026rsquo;s C2 Object Storage excels in many aspects, it\u0026rsquo;s essential to acknowledge certain limitations, well-documented on their official website. Notable constraints include the absence of object-level ACLs and public buckets. Despite these limitations, particularly for data protection use cases, these might not be deal-breakers. Additionally, it should be noted that currently, there are only three regions available: Europe (Frankfurt), North America (Seattle), and APAC (Taiwan), each with a slightly different price point.\nLocation Storage Cost Download overage Cost Europe 6.99EUR / TB 0.01EUR / GB North America 6.99USD / TB 0.01USD / GB APAC 10.99USD / TB 0.03USD / GB When comparing Synology\u0026rsquo;s C2 Object Storage to major hyperscalers, the price difference stands out significantly. However, the market offers other cost-effective options, with Wasabi emerging as a notable competitor. Wasabi has gained attention for its all-inclusive pricing model in Object Storage, mirroring Synology\u0026rsquo;s $6.99/month per TB rate and no egress fees. Yet, Wasabi has a minimum 90-day storage policy, which may not suit those frequently creating and deleting large datasets. Wasabi boasts 13 regions across 12 cities, outshining Synology\u0026rsquo;s three regions and potentially offering better geographical proximity.\nAnother contender is Backblaze B2, offering competitive pricing at approximately $6/month per TB. Similar to Synology, they adopt true monthly pricing, allowing up to 3x the stored data to be downloaded in a month. However, Backblaze B2 introduces charges for some API calls, categorized with included free limits and additional charges, demanding careful consideration to avoid unexpected costs. Like Synology, Backblaze B2 provides data storage in only three regions: US East, US West, or EU Central.\nService Storage Fees Egrees Fees API Fees Synology C2 Object Storage $6.99-10.99 / TB Free up to Storage Purchased Free Wasabi Hot Cloud Storage $6.99 / TB\nMin 90-days Free with fair use\nUp to average storage usage Free with fair use Backblaze B2 $6 / TB Free up to 3x Storage Purchased Some APIs Free, others are charged after initial free limit While each affordable provider has its merits, Synology\u0026rsquo;s C2 Object Storage stands out for its simplicity—a hallmark of the Synology brand. Despite not having the most regions or the highest free data download limits, the peace of mind from not worrying about storage duration or API call usage makes it my preferred choice.\nSo, the next time you\u0026rsquo;re in need of an Object Storage service, consider exploring Synology. They offer a free forever tier providing 15GB, providing a risk-free opportunity to experience the capabilities of Synology\u0026rsquo;s storage solutions firsthand.\n","date":"18 February 2024","externalUrl":null,"permalink":"/2024/02/affordable-cloud-object-storage-synologys-c2-offering/","section":"Posts","summary":"Looking for affordable S3-compatible object storage? Synology C2 offers $6.99/TB/month with no hidden egress fees. Compare it to Wasabi and Backblaze, plus try their free 15GB tier.","title":"Affordable Cloud Object Storage: Synology's C2 offering","type":"posts"},{"content":"Last month, Microsoft unveiled Windows Server Insider build 26040—the inaugural preview branded as Windows Server 2025. As seasoned Windows Server enthusiasts, we’re eager to delve into the enhancements and evolutions this release brings.\nIn this Part 1, we’ll deploy the fresh Windows Server build, meticulously compare available Windows Features and Roles, and scrutinize any modifications to in-box PowerShell modules. Buckle up for an insightful journey through the latest iteration of Windows Server!\nWindows Server 2025 Installation: A Fresh Look # As we fire up the WinPE installer, the changes are immediately apparent. The revamped user interface now resembles the familiar Windows Client installers more than ever. Gone is the old “Microsoft Server Operating System Setup” label; instead, we’re greeted with the reassuring “Windows Server Setup”. And take note: the keyboard input selection screen has vanished.\nBut that’s not all. The installation or repair decision now takes center stage. Three straightforward options—Install, Repair, or switch to the legacy installer—await us. Personally, I find this approach more intuitive than the previous design, where “Repair your computer” was tucked away in the bottom left corner.\nWhile we won’t dissect every screen of the installation process, it’s worth noting that these changes signal a positive shift. Windows Server 2025 is evolving, and I’m here for it!\nComparing Windows Features and Roles: What’s New in Windows Server 2025 # After fresh installations of both operating system versions, we embark on a feature comparison journey. Using the PowerShell command Get-WindowsFeature, I extracted the features and employed Compare-Object to identify differences.\nNetworkATC: A Game-Changer # The standout addition in Windows Server 2025 is the inclusion of NetworkATC—a feature previously exclusive to Azure Stack HCI. For the uninitiated, NetworkATC simplifies networking deployment by adhering to Microsoft’s best practices and minimizing errors. Users define their network intents (e.g., storage-only, VM traffic, or shared management) and can optionally override settings. Notably, this configuration extends beyond individual hosts; it can be applied to entire clusters, ensuring consistent network setups and automatic drift correction.\nHyper-V enthusiasts on Windows Server now enjoy the same robust networking experience as their Azure Stack HCI counterparts.\nFeatures Removed in Windows Server 2025 # With each new Windows edition, there are inevitable casualties—features that no longer make the cut. Windows Server 2025 is no exception. Let’s explore the notable removals:\nPeer Name Resolution Protocol (PNRP): PNRP, once part of Windows Server, has met its end. Security experts have long recommended disabling and removing it due to its vulnerability to exploits like DDoS attacks. SMTP Server and Supporting Tools: A feature that has been on the chopping block since Windows Server 2012, the SMTP Server and its supporting tools have finally bid farewell in Windows Server 2025. Managing SMTP in the IIS6 console (in Windows Server 2022) posed challenges for many users. Nowadays, alternatives like Azure Communication Services, SendGrid, or setting up a Postfix Linux relay have become more popular. Azure Arc Setup Feature: Introduced in Windows Server 2022 via a controversial Windows Update, the Azure Arc Setup feature has now vanished. Although the feature is gone, the Azure Arc Setup taskbar icon remains. To remove it, navigate to HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run in the registry and delete the AzureArcSetup entry. Despite its removal, the feature aimed to simplify Azure Arc onboarding, allowing seamless agent installation and connection to Azure directly from Windows Server. Changes to in-box PowerShell Modules # In-box PowerShell modules have some new additions and updates in this build, but no removals. Here are the main changes:\nNew Modules: DefenderPerformance: Troubleshoot and optimize Defender scanning performance, identify problematic files that slow down scans. LanguagePackManagement: Manage OS language packs. Microsoft.ReFsDedup.Commands: Manage the new ReFS deduplication and compression engine. Microsoft.Windows.Bcd.Cmdlets: Manage BCD entries with native PowerShell commands. Provisioning: Manage provisioning packages. Changed Modules: Get-NetView: Updated to a newer version. Defender: Added a rollback command. Appx: Added MSIX commands. Dism: Added commands for app provisioning, likely APPX/MSIX related. International: Copy international settings from user to system. NetSecurity: Added commands for managing firewall rules for WSLv2 containers. SmbShare: Added commands for SMB over QUIC functionality. Storage: Added Convert-PhysicalDisk command that appears to be for converting existing disks into Storage Spaces volumes. You can see more about the changes to the Powershell modules in this GitHub repository I\u0026rsquo;ve setup\nIn Conclusion: Windows Server 2025 Unveiled # As we bid farewell to the familiar landscapes of Windows Server 2022, we step into the future with Windows Server 2025. This release brings a blend of evolution and innovation, catering to both seasoned administrators and those embarking on their server journey.\nFrom the streamlined deployment of NetworkATC to the revamped user interface, Windows Server 2025 promises a smoother experience. The removal of legacy features and the addition of powerful modules signal Microsoft’s commitment to modernization.\nAs you explore this new chapter, remember that Windows Server isn’t merely a name change; it represents Microsoft’s ongoing investment in meeting your infrastructure needs. Whether you’re managing virtual workloads, securing data, or optimizing performance, Windows Server 2025 awaits your command.\nAnd stay tuned! In a future article, we’ll delve into the additional capabilities of Hyper-V—features that will elevate your virtualization game. 🚀\n","date":"10 February 2024","externalUrl":null,"permalink":"/2024/02/exploring-windows-server-2025-whats-new-and-whats-changed-part-1/","section":"Posts","summary":"Windows Server 2025 is coming! In Part 1, we explore the new installer UI, compare Windows Features (hello NetworkATC!), note removed features like PNRP and SMTP, and review PowerShell module changes.","title":"Exploring Windows Server 2025: What's New and What's Changed - Part 1","type":"posts"},{"content":"","date":"10 February 2024","externalUrl":null,"permalink":"/categories/windows-server/","section":"Categories","summary":"","title":"Windows Server","type":"categories"},{"content":"","date":"10 February 2024","externalUrl":null,"permalink":"/tags/windows-server/","section":"Tags","summary":"","title":"Windows Server","type":"tags"},{"content":"","date":"10 February 2024","externalUrl":null,"permalink":"/tags/windows-server-2025/","section":"Tags","summary":"","title":"Windows Server 2025","type":"tags"},{"content":"","date":"10 February 2024","externalUrl":null,"permalink":"/tags/windows-server-insider/","section":"Tags","summary":"","title":"Windows Server Insider","type":"tags"},{"content":"","date":"10 February 2024","externalUrl":null,"permalink":"/tags/ws2025/","section":"Tags","summary":"","title":"WS2025","type":"tags"},{"content":"I was setting up Veeam Backup \u0026amp; Replication the other day, testing out the Plug-in for VMware Cloud Director (VCD) to provide Self Service backup and restore, and I hit an unexpected issue when trying to access the extension from the VCD Tenant Portal.\nAccess to XMLHTTPRequest has been blocked by CORS policy After some digging, I came across a single post on the Veeam Forums that made reference to the same issue.\nThe root cause appears to be related to the fact that when this environment was built, and VCD was added to the Veeam B\u0026amp;R Server, VCD was running on an internal URL. It seems Veeam Enterprise Manager uses this URL from Veeam B\u0026amp;R to setup CORS Rules, and so if you are using a different URL internally from Veeam, to what tenants use externally to access VCD, you’ll hit this issue.\nNow one option would be to remove and re-add VCD to the Veeam B\u0026amp;R Console, updating it with the same URL tenants will use to access VCD, but this might not be possible for various reasons.\nSo the option I went with in this environment, was the same solutions provided in the forum post, which involved updating a config file on Veeam Enterprise Manager server.\nThe config file in question can be found here at C:\\Program Files\\Veeam\\Backup and Replication\\Enterprise Manager\\WebApp\\Web.config\nIn this file, there is a property called vcdIpOrDnsAddress that needs to be uncommented and updated with the URL tenants access VCD on.\n\u0026lt;?xml version=\u0026#34;1.0\u0026#34; encoding=\u0026#34;utf-8\u0026#34;?\u0026gt; \u0026lt;configuration\u0026gt; \u0026lt;appSettings\u0026gt; ........ \u0026lt;add key=\u0026#34;title\u0026#34; value=\u0026#34;Veeam Backup Enterprise Manager\u0026#34; /\u0026gt; \u0026lt;add key=\u0026#34;vsphere_title\u0026#34; value=\u0026#34;Self-Service Backup Portal\u0026#34; /\u0026gt; \u0026lt;add key=\u0026#34;vcloud_title\u0026#34; value=\u0026#34;Self-Service Backup Portal\u0026#34; /\u0026gt; \u0026lt;add key=\u0026#34;useWindowsAuth\u0026#34; value=\u0026#34;true\u0026#34; /\u0026gt; \u0026lt;add key=\u0026#34;saml:loginUrl\u0026#34; value=\u0026#34;/Saml2/SignIn\u0026#34; /\u0026gt; \u0026lt;add key=\u0026#34;signalR:EnableCrossDomain\u0026#34; value=\u0026#34;true\u0026#34; /\u0026gt; \u0026lt;!--\u0026lt;add key=\u0026#34;applicationUrl\u0026#34; value=\u0026#34;https://localhost:9443/\u0026#34;/\u0026gt;--\u0026gt; \u0026lt;!--\u0026lt;add key=\u0026#34;security-headers:vcdIpOrDnsAddress\u0026#34; value=\u0026#34;\u0026#34; /\u0026gt;--\u0026gt; \u0026lt;/appSettings\u0026gt; ..... After updating the file, restart IIS for it to pick up the changes. You can config this has worked after in IIS Manager by looking at the HTTP Response Headers on the VeeamBackup Website and confirm the CORS Settings have been configured correctly\nOnce that’s all setup, the Veeam plugin should be back up and running in VCD and your tenants can start performing their own backups and restores!\n","date":"18 December 2022","externalUrl":null,"permalink":"/2022/12/fixing-cors-error-when-adding-veeam-plugin-to-vmware-cloud-director/","section":"Posts","summary":"Hit a CORS error in the Veeam VCD plugin? The fix is simple: update vcdIpOrDnsAddress in Veeam Enterprise Manager’s Web.config to match the external URL tenants use to access VCD.","title":"Fixing CORS Error when adding Veeam Plugin to VMware Cloud Director","type":"posts"},{"content":"","date":"18 December 2022","externalUrl":null,"permalink":"/tags/veeam-backup--replication/","section":"Tags","summary":"","title":"Veeam Backup \u0026 Replication","type":"tags"},{"content":"","date":"18 December 2022","externalUrl":null,"permalink":"/tags/veeam-enterprise-manager/","section":"Tags","summary":"","title":"Veeam Enterprise Manager","type":"tags"},{"content":"","date":"18 December 2022","externalUrl":null,"permalink":"/tags/vmware-cloud-director/","section":"Tags","summary":"","title":"VMware Cloud Director","type":"tags"},{"content":"","date":"25 May 2021","externalUrl":null,"permalink":"/tags/aks-hci/","section":"Tags","summary":"","title":"AKS-HCI","type":"tags"},{"content":"","date":"25 May 2021","externalUrl":null,"permalink":"/categories/azure/","section":"Categories","summary":"","title":"Azure","type":"categories"},{"content":"","date":"25 May 2021","externalUrl":null,"permalink":"/tags/azure-arc/","section":"Tags","summary":"","title":"Azure Arc","type":"tags"},{"content":"","date":"25 May 2021","externalUrl":null,"permalink":"/tags/azurestackhci/","section":"Tags","summary":"","title":"AzureStackHCI","type":"tags"},{"content":"Every year, Microsoft holds its annual BUILD conference where they \u0026ldquo;announce new tools and solutions to empower developers to solve real world problems\u0026rdquo;, it\u0026rsquo;s also a great time to pick up some new skills and connect with the wider developer communities.\nIf you\u0026rsquo;ve attended any of the Microsoft conferences in the last few years, you would\u0026rsquo;ve seen a steady increase in hybrid content and solutions, as the world starts to realise that \u0026lsquo;Cloud-native\u0026rsquo; doesn\u0026rsquo;t need to mean \u0026lsquo;Cloud-only\u0026rsquo;. This year\u0026rsquo;s Microsoft BUILD conference is no different.\nAzure Arc # Azure Arc is quickly becoming a gateway to Azure for companies looking to adopt Hybrid Cloud, as not only does it allow publishing on-prem resources up into Azure Resource Manager, but more Azure services are finding their way down to the edge through Azure Arc. This currently involves Azure Arc enabled Kubernetes, Azure Arc enable SQL Server and Azure Arc enabled Data Services.\nApp Services # Azure App Service enables developers to build and host web apps, mobile back ends, and RESTful APIs in the programming language of their choice without managing infrastructure.\nApp services are now \u0026ldquo;Arc Enabled\u0026rdquo;, meaning that its services are coming down to the edge for developers to now deploy to any Arc enabled Kubernetes Cluster, allowing access to Web Apps, Functions, API gateways, Logic Apps and Event Grid. Features such as deployment slots for A/B testing, out-of-box connectors and storage queue triggers are available anywhere you can run Kubernetes.\nDevelopers can now develop code against App services to deploy on Azure, on-prem and any other cloud, allowing for massive code re-use and true hybrid cloud capabilities. Enabling true application portability that allows organisations to start their digital transformation on-prem, migrating components to Azure and other clouds as and when it makes sense, with minimal code changes.\nAdditional Links:\nBuild cloud-native applications that run anywhere - MSBuild Session Build cloud-native applications that run anywhere - Announcement Blog App Service on Azure Arc - Microsoft Docs Open Service Mesh # Much like the preview of Open Service Mesh (OSM) for AKS Clusters on Azure, Azure Arc enables Kubernetes clusters can now have OSM onboarded with ease for a single cluster or with Azure Policy across multiple clusters. This enables another layer of consistency between an application running on AKS in Azure and Kubernetes clusters hosted elsewhere, with OSM making it even easier to build extensible distributed applications across clusters, sites and clouds.\nFor those less familiar with Open Service Mesh, it includes several features for securing traffic between components in an application stack through mTLS and short-lived certificates, traffic management policies for TCP and HTTP communication, as well as tracing and observability insights for troubleshooting and debugging services.\nAdditional Links:\nAzure Arc enabled Open Service Mesh is now in public preview! - Announcement Blog Azure Arc-enabled Open Service Mesh (Preview) - Microsoft Docs Try it out with the Azure Arc Jumpstart runbook Azure Stack HCI # Azure Stack HCI is the evolution of Microsoft Hyper-Converged Infrastructure (HCI) Stack, natively integrated with Azure and Azure Arc, allowing companies to modernise their on-prem infrastructure while still taking advantage of things like Azure great support structure.\nMulti-Cluster Monitoring # While Windows Admin Center is great for investigating the health of a single Azure Stack HCI Cluster, as you scale out to additional clusters and potentially additional sites, there is a need for that monitoring to adapt and scale out with it.\nBuilding on top of Azure Monitor, you can now monitor the health and core metrics of multiple Azure Stack HCI Clusters from the Azure Portal, as well as set up alerts for those critical metrics when things don\u0026rsquo;t look so good.\nUsing Azure Stack HCI insights, you can now monitor more than 400 metrics and events for VMs, Storage and Cluster Performance across a nearly unlimited number of Azure Stack HCI clusters, anywhere in the world.\nAdditional Links:\nAzure Monitor Insights for Azure Stack HCI - Microsoft Docs Monitor multiple clusters - Microsoft Docs Preview Channel # And to support these monitoring capabilities and many, many more features, Microsoft announced a new Preview Channel for Azure Stack HCI. Customers can now try out the latest and greatest features on Azure Stack HCI ahead of GA through regular over-the-air updates, rolled out through Cluster-aware updating.\nSome of the initial features available in the preview channel include:\nNetwork ATC for intent-based management of host networking Dynamic processor compatibility mode for mixed hardware environments Storage thin provisioning for S2D Volumes Support for GPUs on Clustered VMs, allowing for failover on host failure Additional Links:\nWhat’s new for Azure Stack HCI at Build 2021 - Microsoft Blog Network ATC in Preview on Azure Stack HCI - Microsoft Blog AKS on Azure Stack HCI # Over the last 8 months since Microsoft announced AKS on Azure Stack HCI at Microsoft Ignite 2020 there has been several previews released for the new service, however, it has rapidly reached GA Status now at BUILD 2021. Building on top of Azure Stack HCI, AKS-HCI provides a turn-key solution for simple deployment and lifecycle management of Kubernetes clusters on-prem through both PowerShell and Windows Admin Center. AKS-HCI provides full support for Azure Arc out-of-the-box, following Azure AKS design principles and best practices.\nTo make AKS-HCI the best platform for transforming .Net Core and Framework based applications, it takes advantage of many newly developed features like GMSA non-domain joined hosts for Active Directory integrated applications, as well as native Active Directory authentication for delegating access to K8s clusters.\nBecause AKS-HCI is an Azure Service, much like Azure Stack HCI, there are inherent benefits over alternative Kubernetes products when it comes to integrating with Azure Arc and other services. There is no additional cost for taking advantage of Azure Policy and GitOps Configuration through Azure Arc when managing AKS-HCI Clusters for example. And of course, AKS-HCI is the preferred platform for deploying the new Azure Arc enabled App Services to a data centre near you.\nAdditional Links:\nAzure Kubernetes Service on Azure Stack HCI now Generally Available - Announcement Blog Evaluate AKS on Azure Stack HCI Windows Admin Center # And of course, it wouldn\u0026rsquo;t be a Microsoft Conference without a new release of Windows Admin Center these days!\nAt BUILD 2021, WAC v2103.2 has been released with new Cluster-aware updating superpowers for Azure Stack HCI, a massive make-over for the Windows Events tool, a new Windows Time Service extension for managing those pesky Windows Time settings and an improved Containers extensions for assisting with packing applications for deployment to AKS and AKS-HCI.\nYou can read more about these improvements and more on the official announcement post from Microsoft\nWrapping up # Well, that was quite a lot of information for the first day of Microsoft Build 2021.\nWith all the announcements, you can now provide an end-to-end Microsoft solution that spans both Azure and on-prem with consistent tooling and management experiences, through the use of Azure Stack HCI for your infrastructure, AKS-HCI for your Azure Arc enabled Kubernetes cluster, publishing your Web Apps, Azure Functions and Logic Apps across your hybrid cloud environment supported by Managed Instances of SQL Server for persistent data storage.\nWhile Cloud-native started in the public cloud, it\u0026rsquo;s now rushing down to the Edge through key investments in Azure Arc, Azure Stack HCI and AKS. While most of these services are in Preview today, I don\u0026rsquo;t imagine it will take long for them to reach GA status, with more services to follow close behind based on the pace Microsoft is pushing things out.\nHybrid is king, and here to stay.\nFor more information on this and many more of the annoucements at Microsoft Build 2021, go check out the Book of News.\n","date":"25 May 2021","externalUrl":null,"permalink":"/2021/05/hybrid-cloud-announcements-ms-build-2021/","section":"Posts","summary":"MS Build 2021 brought exciting hybrid cloud news! Azure Arc gets App Services, Functions, and Open Service Mesh. Azure Stack HCI gains multi-cluster monitoring. Here’s what matters for hybrid environments.","title":"Hybrid Cloud Announcements | MS Build 2021","type":"posts"},{"content":"","date":"25 May 2021","externalUrl":null,"permalink":"/tags/msbuild/","section":"Tags","summary":"","title":"MSBuild","type":"tags"},{"content":"","date":"13 October 2020","externalUrl":null,"permalink":"/tags/azure-keyvault/","section":"Tags","summary":"","title":"Azure KeyVault","type":"tags"},{"content":"One of the awesome features of Azure VMs has been that they have their own identity in Azure AD, much like traditional servers on-prem have had computer accounts in Active Directory, and these identities can be used to authenticate against other Azure services such as Azure KeyVault.\nThanks to this native ability, it\u0026rsquo;s been possible to securely store objects such as secrets for User accounts, API Keys and things like Certificates in KeyVault and access them from other Azure Resources without having to create and store credentials those services. However, this feature has only been available for native Azure resources until now.\nFor the rest of this post, I will assume that you\u0026rsquo;ve already deployed an Azure Arc agent to a Windows machine. However, if this is not the case, I recommend heading over to the docs.microsoft.com page for more details on this.\nAccessing the Azure Arc enabled servers agent # Just like with Azure VMs, when Azure Arc is deployed to a traditional server, the agent exposes an instance of the Azure Instance Metadata Service.\nHowever, there is a slight difference in that the Azure Arc agent exposes this on http://127.0.0.1:40342, rather than http://169.254.169.254 like the native Azure agent. Apart from that, as you can see it can be queried just like normal.\nThis endpoint address is stored in an environment variable called IDMS_ENDPOINT for easy access though.\nFinding the Token # When it comes to getting a token, the process is similar to native Azure VMs, however, there are some slight differences.\nWith Azure VMs, you can just query the /metadata/identity/oauth2/token endpoint for the agent, and get a token back straight away. But with Azure Arc, you need to prove you have rights to access the token but responding to a challenge.\nThe process is fairly straight forward:\nSend an HTTP request to the Azure Arc Endpoint - http://localhost:40342/metadata/identity/oauth2/token or the environment variable IDENTITY_ENDPOINT Capture the response Read the contents of the WWW-Authenticate header in the response, to find the path to the local challenge token Get the contents of that local file Send another HTTP Request to the Azure Arc Endpoint, but this time including the contents of that local file as the Authorization header. In Powershell, the steps would look like this if we wanted a token for querying Azure resources:\n# Get Arc API Token try { Invoke-WebRequest -UseBasicParsing -Uri \u0026#34;http://localhost:40342/metadata/identity/oauth2/token?api-version=2019-11-01\u0026amp;resource=https%3A%2F%2Fmanagement.azure.com%2F\u0026#34; -Headers @{ Metadata = \u0026#34;true\u0026#34; } -Verbose:0 } catch { $response = $_.Exception.Response } # Extract the path to the challenge token $tokenpath = $response.Headers[\u0026#34;WWW-Authenticate\u0026#34;].TrimStart(\u0026#34;Basic realm=\u0026#34;) # Show Path to Challenge Token $tokenpath # Read the token $token = Get-Content $tokenpath # Acquire Access Token $AzureArcToken = Invoke-RestMethod -UseBasicParsing -Uri \u0026#34;http://localhost:40342/metadata/identity/oauth2/token?api-version=2019-11-01\u0026amp;resource=https%3A%2F%2Fmanagement.azure.com%2F\u0026#34; -Headers @{ Metadata = \u0026#34;true\u0026#34;; Authorization = \u0026#34;Basic $token\u0026#34; } # Show returned token $AzureArcToken Now let\u0026rsquo;s see it in action\nAssigning access to an Azure KeyVault # Now that we\u0026rsquo;ve been able to access a token, we\u0026rsquo;re only halfway there. We now need to assign the Azure Arc identity access to the KeyVault itself.\nThrough the Azure Portal, navigate to the KeyVault instance you want to grant access to, go to Access Policies and click Add Access Policy\nSelect the permissions you want to grant, in this case, Secret Management, and then click None Selected beside the Select principal to add the machine.\nUse the search function to locate your Azure Arc identity, select it and any others you want to add and click Select\nClick the Add Button back on the Add Access Policy screen, and you\u0026rsquo;ll see your new policy has been successfully created.\nFor steps on how to perform this action via Azure Powershell, see the Microsoft Docs page.\nAccessing a KeyVault # Normally at this point, you would be able to use the Connect-AzAccount -Identity command in your Azure VM to authenticate with your managed service identity before running the normal Get-AzKeyVaultSecret commands, however, this isn\u0026rsquo;t currently compatible with the Azure Arc Endpoint.\nSo instead we\u0026rsquo;re limited to making native API calls to the KeyVault service instead.\nLuckily Microsoft documents all their APIs pretty well on docs.microsoft.com, so this isn\u0026rsquo;t too hard to work out.\nBefore we run through a few examples of accessing the Azure KeyVault APIs, here is a quick function to make retrieving the Azure Arc Identity token a little easier.\nFunction Get-AzureArcToken { [cmdletbinding()] param( [string]$ResourceURI ) # Build up URL $SafeString = [System.Net.WebUtility]::URLEncode($ResourceURI) $URI = \u0026#34;http://localhost:40342/metadata/identity/oauth2/token?api-version=2019-11-01\u0026amp;resource={0}\u0026#34; -f $SafeString # Get Arc API Token try { Invoke-WebRequest -UseBasicParsing -Uri $uri -Headers @{ Metadata = \u0026#34;true\u0026#34; } -Verbose:0 } catch { $script:response = $_.Exception.Response } # Extract the path to the challenge token $tokenpath = $script:response.Headers[\u0026#34;WWW-Authenticate\u0026#34;].TrimStart(\u0026#34;Basic realm=\u0026#34;) # Read the token $token = Get-Content $tokenpath # Acquire and return Access Token Invoke-RestMethod -UseBasicParsing -Uri $uri -Headers @{ Metadata = \u0026#34;true\u0026#34;; Authorization = \u0026#34;Basic $token\u0026#34; } } List Secrets in an Azure KeyVault # A common scenario will be finding out what secrets are currently available in a KeyVault instance.\nTo do this, we need to get a Token for interacting with the KeyVault API, and then make a call to the /Secrets endpoint.\nThis endpoint is fairly basic, all we can specify is the API version and the maximum number of results we want to be returned.\nIn this example, we will be querying a KeyVault instance called blogdemo and so the URL for our query will be https://blogdemo.vault.azure.net.\n# Get an Azure KeyVault Access Token with new Function $AccessToken = Get-AzureArcToken -ResourceURI \u0026#39;https://vault.azure.net\u0026#39; # Setup Query Attributes $Query = @{ Uri = \u0026#34;https://blogdemo.vault.azure.net/secrets?api-version=7.1\u0026#34; Method = \u0026#34;Get\u0026#34; Headers = @{ Authorization = \u0026#34;Bearer $($AccessToken.access_token)\u0026#34; } } # Retrieve Secrets Invoke-RestMethod @Query | Select-Object -ExpandProperty Value | fl * Get Secret Content # Now that we know there are secrets stored in the vault, we probably want to view the contents of one of them.\nThe endpoint this time is the value of the ID field in the output of our previous query. But if you know the name of the secret you want to query, you can work out the URL by adding it to the end of the path for the previous query. In our case, this means that to query secret1 the URL is https://blogdemo.vault.azure.net/secrets/secret1.\n# Get an Azure KeyVault Access Token with new Function $AccessToken = Get-AzureArcToken -ResourceURI \u0026#39;https://vault.azure.net\u0026#39; # Setup Query Attributes $Query = @{ # URI of the specific secret we want Uri = \u0026#34;https://blogdemo.vault.azure.net/secrets/secret1?api-version=7.1\u0026#34; Method = \u0026#34;Get\u0026#34; Headers = @{ Authorization = \u0026#34;Bearer $($AccessToken.access_token)\u0026#34; } } # Retrieve Secrets Invoke-RestMethod @Query | Select-Object -ExpandProperty Value | fl * Create new Secret # Viewing existing secrets is good, but being able to create new secrets is just as important.\nMuch like the previous API calls we\u0026rsquo;ve made, we will be using the /secrets/{secretname} endpoint, only this time it will be a PUT request rather than a GET request.\nThis is because we need to provide information on the secret we want to store, at a minimum the secret itself.\nThere are several useful additional details you can provide including but not limited to:\nContent Type Expiry Date Azure Resource Tags These are all documented in RestAPI reference page.\nHere we\u0026rsquo;re creating a new secret call DemoSecret, with the secret value Anything1sPossible!, and expiry date 30 days in the future and some Azure tags.\n# New Secret Name $SecretName = \u0026#34;DemoSecret\u0026#34; # Get an Azure KeyVault Access Token with new Function $AccessToken = Get-AzureArcToken -ResourceURI \u0026#39;https://vault.azure.net\u0026#39; # Setup Secret Attributes $SecretAttributes = @{ value = \u0026#34;Anything1sPossible!\u0026#34; contentType = \u0026#34;plaintext\u0026#34; attributes = @{ # Expiry Date is in 30 days time exp = [datetimeoffset]::UtcNow.AddDays(30).ToUnixTimeSeconds() } tags = @{ use = \u0026#34;powershell\u0026#34; demo = \u0026#34;yes\u0026#34; } } # Setup Web Request $WebRequest = @{ Uri = \u0026#34;https://blogdemo.vault.azure.net/secrets/$($SecretName)?api-version=7.1\u0026#34; Method = \u0026#34;Put\u0026#34; ContentType = \u0026#34;application/json\u0026#34; Headers = @{ Authorization = \u0026#34;Bearer $($AccessToken.access_token)\u0026#34; } Body = ($SecretAttributes | ConvertTo-Json) } # Create Secret Invoke-RestMethod @WebRequest Delegating access to Azure Arc tokens # Now that we\u0026rsquo;ve looked at how powerful the Azure Arc tokens can be, you might be wondering about delegating or securing access to them.\nBy default, Users with Local Admin rights have access, however, when you install the Azure Arc agent on a machine, it creates a new local security group called Hybrid agent extension applications.\nThis security group allows access to the folder where the Arc challenge tokens are generated for authenticating against the IDMS Endpoint.\nWrapping up # As you can see, Azure Arc is lighting up more and more hybrid scenarios, and enabling you to operate in a cloud mentality on-prem, just like you do in Azure.\nYou can now access Azure Resources with Managed Service Identity access tokens, such as Azure KeyVault, rather than creating SPNs and trying to securely store and rotate their credentials.\nIn future, you could even look to use this to rotate and store the local administrator account credentials in Azure KeyVault for on-prem machines, much like LAPS does today, but without Active Directory. This would bring the security enhancements of LAPS to non-domain joined machines or sensitive workloads like backup servers.\nAs always, feel free to reach out to me here, or on Twitter (@NZ_BenThomas) and let me know what you thought of this post, or any follow-up questions you might have about it!\n","date":"13 October 2020","externalUrl":null,"permalink":"/2020/10/using-an-azure-arc-token-to-access-azure-keyvault/","section":"Posts","summary":"Azure Arc gives on-prem servers their own Azure AD identity. This guide shows how to retrieve an Azure Arc token and use it to securely access secrets, keys, and certificates in Azure KeyVault—no stored credentials needed.","title":"Using an Azure Arc Token to access Azure KeyVault","type":"posts"},{"content":"","date":"28 September 2020","externalUrl":null,"permalink":"/categories/azurestackhci/","section":"Categories","summary":"","title":"AzureStackHCI","type":"categories"},{"content":"As some of you might have seen earlier this month, I tweeted my excitement at the fact that the Azure Stack HCI 20H2 preview included a newly rebuilt SConfig utility, written in PowerShell!\nIncase you missed it, #AzureStackHCI includes a completely re-written version of SConfig! The best part? It\u0026#39;s written in #PowerShell, so why not start extending it? :D I spent a couple of minutes and added a little extra menu for my own use#MVPBuzz #AzSHCI pic.twitter.com/JyUmFiM4hC\n\u0026mdash; Ben Thomas | @ben.hybridby.design BlueSky (@NZ_BenThomas) September 11, 2020 For those not familiar with SConfig, it has been an important tool for Server Core users for a while now, as, without a GUI, it is the quickest and easier way to perform basic maintenance and troubleshooting (at least until Windows Admin Center).\nSome of the tasks it\u0026rsquo;s capable of include:\nJoining a Domain or Workgroup Changing the Computer name Enabling Remote Management Enabling Remote Desktop Finding and applying Windows Updates Changing IP Address and DNS Settings Changing Date and Time settings But these were all written in VBScript, a language long replaced by PowerShell, and so SConfig remained largely untouched from when it originally turned up in Windows Server 2008.\nNow that it has been rewritten, I\u0026rsquo;m sure Microsoft has plans to improve its capabilities, but in the meantime, I thought I\u0026rsquo;d give it a go.\nxSConfig # Enter the xSConfig PowerShell Module.\nThe idea behind this module is to take the new SConfig module as a base and expand it to do more. In its current form, it\u0026rsquo;s very basic, but I wanted to get something out quickly to show what was possible now, and also get feedback on where people want to see it going.\nCurrently, it\u0026rsquo;s limited to the following:\nAdding a new \u0026lsquo;Extra\u0026rsquo; menu option to the home screen of SConfig Displaying the name of the Cluster the node is part of Whether or not Storage Spaces Direct (S2D) is enabled or not What the health status of the Storage Subsystem is if S2D is enabled The number of Storage Pools and their names/health/size/utilization The number of Virtual Disks and their names/health/size/utilization The nodes in the cluster and their statuses Demo # This is all well and good, but below you can see a demo of this in action!\nInstalling the Module # Now, because this needs the new SConfig Module, it\u0026rsquo;s only compatible with the new Azure Stack HCI 20H2 OS (for now).\nThe module is published to the PSGallery, so it can be installed like any other module\nInstall-Module -Name xSConfig Once it\u0026rsquo;s installed, you can access it any time by leaving the default SConfig menu (option 15) and invoking it with\nInvoke-xSConfig Where to next # Well, the module is very basic at the moment, so I have some ideas around where I want to go next, but what I want is feedback from the community!\nSo please, download the module, give it a try, and then head over to GitHub and let me know what you think! Raise issues for features you want to see, raise issues for bugs you hit, raise Pull Requests if you want to add your enhancements even.\nIn the meantime, I\u0026rsquo;m going to be working on finishing up the Unit tests for what\u0026rsquo;s there already and getting an Azure DevOps Pipeline in place to help out, and then you might see some more features coming\u0026hellip;\nCreating Virtual Disks Expanding Virtual Disks Creating Clusters Adding Cluster nodes Managing Virtual Switches Deploying AKS on HCI The possibilities are nearly endless with PowerShell under the hood.\nI look forward to hearing what everyone thinks, so let me know, on here, on Twitter (@NZ_BenThomas) or anywhere else you find me!\n","date":"28 September 2020","externalUrl":null,"permalink":"/2020/09/extending-sconfig-in-azure-stack-hci-20h2/","section":"Posts","summary":"Azure Stack HCI 20H2 rebuilt SConfig in PowerShell! I’ve created xSConfig to extend it with cluster info, S2D status, storage pool details, and node health—all from the familiar SConfig interface.","title":"Extending SConfig in Azure Stack HCI 20H2","type":"posts"},{"content":"","date":"28 September 2020","externalUrl":null,"permalink":"/tags/s2d/","section":"Tags","summary":"","title":"S2D","type":"tags"},{"content":"","date":"28 September 2020","externalUrl":null,"permalink":"/tags/storage-spaces-direct/","section":"Tags","summary":"","title":"Storage Spaces Direct","type":"tags"},{"content":"","date":"2 March 2020","externalUrl":null,"permalink":"/tags/cache/","section":"Tags","summary":"","title":"Cache","type":"tags"},{"content":"So you\u0026rsquo;ve set up an Azure Stack HCI Cluster and everything\u0026rsquo;s running great, but there is this nagging feeling in the back of your mind. It\u0026rsquo;s a hybrid setup, with some type of flash cache sitting in front of spinning disk, and you start to wonder how hard you\u0026rsquo;re pushing that cache, and how long it will last.\nThankfully with Windows Server 2019, there are many in-built tools and commands to help work out just that!\nIn this post, we are going to look at:\nWhere\u0026rsquo;s my cache? Storage History commands Looking back with Cluster Performance History Pulling it all together into a new tool So what\u0026rsquo;s next? Additional reading Where\u0026rsquo;s my cache? # Storage Spaces Direct, the technology responsible for that super-fast storage in your Azure Stack HCI deployment, does a great job of hiding away all the boring details and steps when you build a cluster. It simplifies the whole process down to two commands, New-Cluster and Enable-ClusterS2D.\nBut don\u0026rsquo;t worry, identifying your cache drives is still just as simple once things are up and running. They\u0026rsquo;re identifiable from the usage property of a physical disk, and you can find them with a simple command\nGet-PhysicalDisk -Usage Journal This will return a nice table of all those cache drives (see below). So now we have our cache drives, let\u0026rsquo;s look at what they\u0026rsquo;ve been up to.\nDeviceId FriendlyName SerialNumber MediaType CanPool OperationalStatus HealthStatus Usage Size -------- ------------ ------------ --------- ------- ----------------- ------------ ----- ---- 2001 ATA INTEL SSDSC2BA80 BTHV00000000000OGN SSD False OK Healthy Journal 745.21 GB 1003 ATA INTEL SSDSC2BA80 BTHV00000000000OGN SSD False OK Healthy Journal 745.21 GB 1002 ATA INTEL SSDSC2BA80 BTHV00000000000OGN SSD False OK Healthy Journal 745.21 GB 2003 ATA INTEL SSDSC2BA80 BTHV00000000000OGN SSD False OK Healthy Journal 745.21 GB 2002 ATA INTEL SSDSC2BA80 BTHV00000000000OGN SSD False OK Healthy Journal 745.21 GB 1000 ATA INTEL SSDSC2BA80 BTHV00000000000OGN SSD False OK Healthy Journal 745.21 GB 1001 ATA INTEL SSDSC2BA80 BTHV00000000000OGN SSD False OK Healthy Journal 745.21 GB 2000 ATA INTEL SSDSC2BA80 BTHV00000000000OGN SSD False OK Healthy Journal 745.21 GB Storage History commands # One of the many commands added in Windows Server 2019 to make our lives easier is Get-StorageHistory\nThis command will go retrieve several stored stats, some from the SMART data on the disks, and others maintained by the OS.\nRetrieving data about a disk is as easy as passing it through to the command!\nPS \u0026gt; Get-PhysicalDisk -Usage Journal | Get-StorageHistory DeviceNumber FriendlyName SerialNumber BusType MediaType TotalIoCount FailedIoCount AvgIoLatency(us) MaxIoLatency(us) EventCount 256us 1ms 4ms 16ms 64ms 128ms 256ms 2s 6s 10s ------------ ------------ ------------ ------- --------- ------------ ------------- ---------------- ---------------- ---------- ----- --- --- ---- ---- ----- ----- -- -- --- 2001 ATA INTEL SSDSC2BA80 BTHV00000000000OGN SAS SSD 645,141,521 84 598.9 513,106.8 246 61 3 110 34 27 1 10 1003 ATA INTEL SSDSC2BA80 BTHV00000000000OGN SAS SSD 1,317,886,434 73 1,375.2 515,510.1 244 62 1 104 37 16 24 1002 ATA INTEL SSDSC2BA80 BTHV00000000000OGN SAS SSD 1,326,895,280 76 1,522.3 517,003.1 244 62 2 100 40 18 22 2003 ATA INTEL SSDSC2BA80 BTHV00000000000OGN SAS SSD 969,169,213 136 710.7 513,710.2 246 61 4 96 45 22 2 16 2002 ATA INTEL SSDSC2BA80 BTHV00000000000OGN SAS SSD 1,144,926,978 177 1,872.4 514,277.1 246 62 3 95 45 29 1 11 1000 ATA INTEL SSDSC2BA80 BTHV00000000000OGN SAS SSD 1,171,742,589 71 1,190.9 517,184.0 244 61 3 104 36 20 20 1001 ATA INTEL SSDSC2BA80 BTHV00000000000OGN SAS SSD 1,112,541,260 65 1,149.3 514,377.9 244 62 2 113 27 19 21 2000 ATA INTEL SSDSC2BA80 BTHV00000000000OGN SAS SSD 1,079,017,077 157 980.1 513,973.3 246 60 4 92 50 22 1 17 As you can see, the default output of the command has a heavy interest in the latency of the disk, but nothing about how many writes are going to our disks, or what timeframe this is over.\nFocusing in on a single disk, and using Format-List we get more of a picture about the details hidden away about our disk.\nPS \u0026gt; Get-PhysicalDisk -Usage Journal | Select-Object -First 1 | ` \u0026gt;\u0026gt; Get-StorageHistory | Format-List * Version : 10 FriendlyName : ATA INTEL SSDSC2BA80 SerialNumber : BTHV00000000000OGN DeviceId : {268d880b-33a3-6c8c-bc95-f8361285c068} DeviceNumber : 2001 BusType : SAS MediaType : SSD StartTime : 2/14/2020 3:18:55 PM EndTime : 2/25/2020 4:03:54 PM EventCount : 246 MaxQueueCount : 36 MaxOutstandingCount : 32 TotalIoCount : 645141521 SuccessIoCount : 645141437 FailedIoCount : 84 TotalReadBytes : 10794587081216 TotalWriteBytes : 8966117642240 TotalIoLatency : 3864066151996 AvgIoLatency : 5989 MaxIoLatency : 5131068 MaxFlushLatency : 1378 MaxUnmapLatency : 0 BucketCount : 12 BucketIoLatency : {2560, 10000, 40000, 160000...} BucketSuccessIoCount : {293181558, 238929981, 109484596, 3536792...} BucketFailedIoCount : {84, 0, 0, 0...} BucketTotalIoCount : {293181642, 238929981, 109484596, 3536792...} BucketTotalIoTime : {346273222942, 1227862537245, 2109283312866, 176980948128...} BucketIoPercent : {45, 37, 17, 1...} BucketHighestLatencyCount : {61, 3, 110, 34...} Hey there we go, those look more interesting. Now we have both a timeframe to work with and a bytes written counter for the disk. From here we can use some simple maths to determine the average amount of data being written every day.\n$$Daily Write = \\frac{TotalWriteBytes}{(EndTime - StartTime)}$$\nIn Powershell, this is what it would look like\n1 2 3 4 5 6 7 8 9 # Start by collecting our data $CacheDisks = Get-PhysicalDisk -Usage Journal $CacheDisk1 = $CacheDisks | Select-Object -First 1 $StorageHistoryData = $CacheDisk1 | Get-StorageHistory # Now we need to find the timespan $Timespan = New-TimeSpan -Start $StorageHistoryData.StartTime ` -End $StorageHistoryData.EndTime # Finally we get our daily write $StorageHistoryData.TotalWriteBytes / $TimeSpan.TotalDays Looking back with Cluster Performance History # Another great feature introduced in Windows Server 2019 is the Cluster Performance History, and I could write a whole post just on this. At a high level, it gathers performance counters for a huge number of components in a Storage Spaces Direct cluster and saves them to a database over time, allowing for easy querying via Powershell.\nThis is great in our case, as we can drill into the performance data of our cache drives over time without having to worry about having the right monitoring setup in the first place.\nJust as with the Get-StorageHistory command, the Get-ClusterPerf command can be fed physical disks through the pipeline to find their related data.\nPS \u0026gt; Get-PhysicalDisk -Usage Journal | Select -First 1 | Get-ClusterPerf Object Description: PhysicalDisk BTHV00000000000OGN Series Time Value Unit ------ ---- ----- ---- PhysicalDisk.Cache.Size.Dirty 02/26/2020 18:17:56 24.45 GB PhysicalDisk.Cache.Size.Total 02/26/2020 18:17:56 709.01 GB PhysicalDisk.IOPS.Read 02/26/2020 18:18:00 4 /s PhysicalDisk.IOPS.Total 02/26/2020 18:18:00 116 /s PhysicalDisk.IOPS.Write 02/26/2020 18:18:00 112 /s PhysicalDisk.Latency.Average 02/26/2020 18:18:00 99.88 us PhysicalDisk.Latency.Read 02/26/2020 18:18:00 1.06 ms PhysicalDisk.Latency.Write 02/26/2020 18:18:00 63.13 us PhysicalDisk.Throughput.Read 02/26/2020 18:18:00 599.18 KB/S PhysicalDisk.Throughput.Total 02/26/2020 18:18:00 1.19 MB/S PhysicalDisk.Throughput.Write 02/26/2020 18:18:00 615.18 KB/S The obvious performance counter here is PhysicalDisk.Throughput.Write. While this tells us the write throughput of our cache drives, the more interesting stat here is PhysicalDisk.Cache.Size.Dirty. This counter shows how much data is currently in the write cache portion of the disk, over time it will shrink if no new writes come in and the data is flushed through to the capacity disk behind the cache.\nBy default, the Get-ClusterPerf command will only return the most recent data point, giving a limited snapshot of what is going on. Using the -Timeframe parameter we can access data for the last hour, day, week, month or even year!\nUsing a longer period, we can feed the data into Measure-Object to find the average over time.\nPulling it all together into a new tool # While accessing all this data has been pretty easy so far, if you want to start looking at it across multiple drives, and multiple servers in a cluster, then currently that\u0026rsquo;s a lot of manual work.\nAnd so I wrote Get-S2DCacheChurn.ps1, a script that allows you to query a cluster and return this data from all cache disks in all cluster nodes.\nUsing the commands we\u0026rsquo;ve already looked at, we can use the size of the cache drives, and the average daily write we calculated, to estimate the Drive Writes per Day (DWPD) stat.\nSo putting it all together, the output looks a little like this\nCluster ComputerName Disk Size EstDwpd AvgDailyWrite AvgWriteThroughput AvgCacheUsage ------- ------------ ---- ---- ------- ------------- ------------------ ------------- Cluster1 Node1 Slot 0 745.21 GB 1.6x 1.18 TB 19.71 MB/s 3.35 GB Cluster1 Node1 Slot 1 745.21 GB 1.0x 756.15 GB 12.30 MB/s 21.51 GB Cluster1 Node1 Slot 2 745.21 GB 1.8x 1.28 TB 21.25 MB/s 4.45 GB Cluster1 Node1 Slot 3 745.21 GB 1.4x 1.02 TB 16.92 MB/s 2.44 GB Cluster1 Node2 Slot 0 745.21 GB 1.3x 1,000.90 GB 16.17 MB/s 2.23 GB Cluster1 Node2 Slot 1 745.21 GB 1.3x 932.73 GB 15.08 MB/s 2.05 GB Cluster1 Node2 Slot 2 745.21 GB 1.5x 1.11 TB 18.45 MB/s 2.86 GB Cluster1 Node2 Slot 3 745.21 GB 1.5x 1.09 TB 18.07 MB/s 2.49 GB Now we can compare these stats to the specs sheets provided by the drive manufacturers to see if everything is healthy, or if the drives are going to burn through their expected lifetime of writes before you\u0026rsquo;re ready to decommission your cluster.\nThis might seem like something you don\u0026rsquo;t need to worry about, because you\u0026rsquo;ve got warranty after all, but if all of your cache drives have been running for the same amount of time, with similar write usage, then it won\u0026rsquo;t go well for your cluster if they all fail around the same time.\nAs always, the script is up in my Github repo, and you can find it here\nOr if you want to download it and try it out, simply run the below command\n1 2 3 $URL = \u0026#34;https://raw.githubusercontent.com/comnam90/bcthomas.com-scripts/master/Powershell/Scripts/Get-S2DCacheChurn.ps1\u0026#34; Invoke-WebRequest -Uri $URL -UseBasicParsing -OutFile Get-S2DCacheChurn.ps1 .\\Get-S2DCacheChurn.ps1 The script has the following parameters:\nCluster This can be a single Azure Stack HCI Cluster or multiple Clusters LastDay Returns data for only the last 24 hours Anonymize Removes identifiable information from the results, so that they can be shared. So what\u0026rsquo;s next? # Going back to that shiny new Azure Stack HCI Deployment you put in, and how well it\u0026rsquo;s running, remember the job isn\u0026rsquo;t done. Check-in on it, use the tools available to monitor show it\u0026rsquo;s going overtime.\nHave a link about using tools like Azure Monitor, Grafana, InfluxDB, and other modern tools to not just extract this data Adhoc, but continuously. Allowing you to monitor any degradation over time and also alert on major issues.\nAny come on over to the Azure Stack HCI Slack Community, chat to others running clusters like you, hear about what works well for them and issues encountered.\nAnd as always, let me know if you have any further questions, on here, Twitter, or Slack.\nAdditional reading # Choosing drives for Storage Spaces Direct - Microsoft Docs Performance history for Storage Spaces Direct - Microsoft Docs Understanding SSD endurance - TechCommunity Don\u0026rsquo;t do it: consumer-grade solid-state drives (SSD) in Storage Spaces Direct - TechCommunity ","date":"2 March 2020","externalUrl":null,"permalink":"/2020/03/forecasting-azure-stack-hci-cache-wear/","section":"Posts","summary":"Worried about how hard you’re pushing your S2D cache SSDs? This post covers identifying cache disks, querying storage history, using Cluster Performance History, and a new tool to check cache wear across your environment.","title":"Forecasting Azure Stack HCI Cache Wear","type":"posts"},{"content":"","date":"2 March 2020","externalUrl":null,"permalink":"/categories/storage-spaces-direct/","section":"Categories","summary":"","title":"Storage Spaces Direct","type":"categories"},{"content":"","date":"2 March 2020","externalUrl":null,"permalink":"/tags/windows-server-2019/","section":"Tags","summary":"","title":"Windows Server 2019","type":"tags"},{"content":"","date":"2 March 2020","externalUrl":null,"permalink":"/tags/ws2019/","section":"Tags","summary":"","title":"WS2019","type":"tags"},{"content":"","date":"13 October 2019","externalUrl":null,"permalink":"/tags/dfs/","section":"Tags","summary":"","title":"DFS","type":"tags"},{"content":"","date":"13 October 2019","externalUrl":null,"permalink":"/tags/dfs-r/","section":"Tags","summary":"","title":"DFS-R","type":"tags"},{"content":"","date":"13 October 2019","externalUrl":null,"permalink":"/tags/dfsr/","section":"Tags","summary":"","title":"DFSR","type":"tags"},{"content":"DFS Replication (DFS-R) is a fantastic tool in any sysadmins belt when it comes to creating highly redundant and scalable file shares. And yet anyone who has used it, knows that monitoring it can be difficult at the best of times.\nWindows Server 2012 introduced several Powershell commands for DFS-R which help discover partnerships and their status, however none of them test replication end-to-end.\nSo here are the goals I get out to achieve with Powershell:\nTest a file replicates successfully between 2 servers using DFS-R Fail the test if the file doesn\u0026rsquo;t replicate within an expected period Dynamically discover replicated folders Dynamically discover replication groups Dynamically discover replication partners Run both locally and remotely If you don\u0026rsquo;t want to learn how the code works, you can skip to the examples of the script in action, or just download the script here.\nBuilding the Code # The first step is pretty straight forward, create a file and test it arrives at the other side.\n1# Test File Name 2$FileName = \u0026#34;DFSRTest_$(Get-Date -format yyyyMMddmmhhss).txt\u0026#34; 3# Source Server Path 4$SourcePath = \u0026#34;\\\\DFSR01\\Data\\$FileName\u0026#34; 5# Destination Server Pth 6$TargetPath = \u0026#34;\\\\DFSR02\\Data\\$FileName\u0026#34; 7# Create test file 8New-Item -ItemType File $SourcePath | out-null 9 10# Start loop looking for file on destination server 11do { 12 $found = Test-Path -Path $TargetPath 13} until ( $found ) 14Remove-Item $SourcePath -Force 15\u0026#34;DFSR Replication succeeded = $found\u0026#34; Now to make sure this loop doesn\u0026rsquo;t run forever if replication isn\u0026rsquo;t working or there is a large backlog, we need to add a timeout. To do this, we\u0026rsquo;ll use the stopwatch function.\n1# Test File Name 2$FileName = \u0026#34;DFSRTest_$(Get-Date -format yyyyMMddmmhhss).txt\u0026#34; 3# Source Server Path 4$SourcePath = \u0026#34;\\\\DFSR01\\Data\\$FileName\u0026#34; 5# Destination Server Pth 6$TargetPath = \u0026#34;\\\\DFSR02\\Data\\$FileName\u0026#34; 7# Timeout in Minutes 8$Timeout = 5 9# Create and start a stopwatch timer 10$StopWatch = [System.Diagnostics.Stopwatch]::StartNew() 11# Create test file 12New-Item -ItemType File $SourcePath | out-null 13 14# Start loop looking for file on destination server 15do { 16 $found = Test-Path -Path $TargetPath 17} until ( 18 $found -or ` 19 $StopWatch.Elapsed.TotalMinutes -ge $Timeout 20) 21Remove-Item $SourcePath -Force 22\u0026#34;DFSR Replication succeeded = $found\u0026#34; The last 3 steps we can tick off at the same time using DFS-R in-box Powershell to help us. Get-DFSRConnection can be used to query a machine for what connections it\u0026rsquo;s part of, this tells us the group names and the destination servers. With this information, we can then use Get-DFSRMembership to query the folder names and paths to test.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 # Test File Name $FileName = \u0026#34;DFSRTest_$(Get-Date -format yyyyMMddmmhhss).txt\u0026#34; # Source Server $SourceServer = \u0026#34;DFSR01\u0026#34; # Timeout in Minutes $Timeout = 5 # DFSR Groups in the domain $Groups = Get-DFSRConnection -SourceComputerName $SourceServer | Group-object -Property GroupName # Loop through groups Foreach ($Group in $Groups) { $GroupName = $Group.Name $Folders = Get-DFSRMembership -GroupName $GroupName -ComputerName $Group.Group.SourceComputerName, $Group.Group.DestinationComputerName | Group-Object -Property FolderName Foreach ($Folder in $Folders) { $FolderName = $Folder.Name $SourceFolder = $Folder.Group.Where{ $_.ComputerName -eq $SourceServer } $Targets = $Folder.Group.ComputerName.Where{ $_ -ne $SourceServer } Foreach ($Target in $Targets) { $TargetFolder = $Folder.Group.Where{ $_.ComputerName -ne $SourceServer } $SourcePath = \u0026#34;\\\\{0}\\{1}\\{2}\u0026#34; -f $SourceFolder.ComputerName, $SourceFolder.ContentPath.Replace(\u0026#34;:\u0026#34;, \u0026#34;$\u0026#34;), $FileName $TargetPath = \u0026#34;\\\\{0}\\{1}\\{2}\u0026#34; -f $TargetFolder.ComputerName, $TargetFolder.ContentPath.Replace(\u0026#34;:\u0026#34;, \u0026#34;$\u0026#34;), $FileName # Create and start a stopwatch timer $StopWatch = [System.Diagnostics.Stopwatch]::StartNew() # Create test file New-Item -ItemType File $SourcePath | out-null # Start loop looking for file on destination server do { $found = Test-Path -Path $TargetPath } until ( $found -or ` $StopWatch.Elapsed.TotalMinutes -ge $Timeout ) Remove-Item $SourcePath -Force \u0026#34;$FolderName replication from $SourceServer to $Target working = $found\u0026#34; } } } We now have a way to test the folders a server replicates using DFS-R is working. To make this a bit more reusable, I turned the above code into a script that can be fed specific parameters.\nMeet Test-DfsrReplication, a script you can use to test one or more servers, either for a specific folder or all folders. Not only that, but it will test replication in both directions.\nYou can download an up-to-date copy of it any time from my Github account here.\nExamples # And here are some examples of it in action!\n# Test all replicated folders for DFSR01 Test-DfsrReplication -ComputerName DFSR01 | ft -au # Test replication for the Data folder Test-DfsrReplication -ComputerName DFSR01 -Folder Data | ft -au # Test one folder that exists, and one that doesn\u0026#39;t with verbose output Test-DfsrReplication -ComputerName DFSR01 -Folder Data1,Profiles -Verbose | ft -au\u0026lt; As always, please comment if you have any further questions or have found this useful!\n","date":"13 October 2019","externalUrl":null,"permalink":"/2019/10/testing-dfs-replication-with-powershell/","section":"Posts","summary":"Monitoring DFS-R can be difficult. This PowerShell script creates a test file, waits for it to replicate to partner servers, and reports success or failure—with dynamic discovery of replication groups and folders.","title":"Testing DFS Replication with Powershell","type":"posts"},{"content":"","date":"2 September 2019","externalUrl":null,"permalink":"/categories/azurestack/","section":"Categories","summary":"","title":"AzureStack","type":"categories"},{"content":"","date":"2 September 2019","externalUrl":null,"permalink":"/tags/azurestack/","section":"Tags","summary":"","title":"AzureStack","type":"tags"},{"content":"","date":"2 September 2019","externalUrl":null,"permalink":"/tags/updates/","section":"Tags","summary":"","title":"Updates","type":"tags"},{"content":"AzureStack is a fantastic appliance, with a massively simplified patch and lifecycle policy thanks to a lot of hard work from Microsoft and the OEMs delivering it. But even with all that, to ensure the best experience when updating AzureStack, you should always apply the available hotfixes in-between updates.\nAt some point, you may find you’ve fallen more than one update behind and need to catch up. Finding all the right hotfixes and updates requires reading each of the release notes for prerequisites. Or maybe you just want to double check there are no hotfixes you’ve missed since the last time you updated.\nTo save time and simplify the process, I’ve put together a Powershell function that can show you all the available updates for your release or specific version, including prerequisites.\nBring on the Powershell # Find-AzSAvailableUpdate is designed to be a simple to use, whether you want to find out the latest update, or what updates you need to get there.\nAvailable Parameters # Version: Supply a specific version in the 1.1906.0.30 format, OR Release: Supply a release number in the 1906 format LatestOnly: Switch that returns the latest update details SimpleOutput: Returns results in a string rather than an object. Examples # Find-AzSAvailableUpdate -Version 1.1907.12.44 This will query for updates to the specific version 1.1907.12.44 and return the results as an array of powershell objects.\nFind-AzSAvailableUpdate -Release 1807 | ft -au\u0026lt; This will look for all updates since AzureStack 1807 was originally released, and display them in a formatted table.\nFind-AzSAvailableUpdate -Release 1907 -SimpleOutput This will return the results as a simplified string, showing the update versions that need to be applied.\nSo how do you get this Powershell function? Github of course! This copy will be maintained with future improvements and fixes.\nIf you run into any issues, or just want to share how you\u0026rsquo;re making use of this function, leave a comment below\n","date":"2 September 2019","externalUrl":null,"permalink":"/2019/09/updating-your-azurestack-make-sure-you-dont-miss-any-steps/","section":"Posts","summary":"Finding all the right AzureStack hotfixes between updates requires reading multiple release notes. Find-AzSAvailableUpdate simplifies this by showing all updates needed for your version, including prerequisites.","title":"Updating your AzureStack? Make sure you don't miss any steps!","type":"posts"},{"content":"","date":"1 June 2019","externalUrl":null,"permalink":"/tags/azshci/","section":"Tags","summary":"","title":"AzSHCI","type":"tags"},{"content":" Overview # While spending a lot of time on the Storage Spaces Direct Slack group, one thing that comes up, again and again, is patching of S2D Clusters, and what is the best way to do it.\nFor this blog series, I\u0026rsquo;m going to break down the patching best practices into 2 separate scenarios:\nOffline Patching Using Cluster Aware Updating Offline Patching # Offline patching is a pretty common scenario when patching S2D Clusters, and in my mind it is used for 2 reasons, catching up on multiple months of patching where there are known issues, and planned patching in a small window with an outage.\nThe process is pretty straight forward, shut everything in the cluster down, patch the hosts, and start it all back up again. But this means your highly available platform isn\u0026rsquo;t that available, so why do it?\nPros # The main advantages to offline patching is that there is no risk of VMs experiencing unexpected reboots because they\u0026rsquo;re already powered off, and for the same reason, there is no risk to the storage volumes provided by Storage Spaces Direct.\nAnd you can patch and reboot all nodes at the simultaneously because there are no storage jobs that need to run when all of the CSVs are offline.\nCons # The obvious disadvantage, of course, is the fact that you need to arrange a business outage to shut everything down for patching, however, this outage only needs to be 1-2 hours.\nSteps # The below steps are based on the instructions provided by Microsoft on Docs.Microsoft.com\nPlan your maintenance window. Shutdown all VMs on the cluster Take the virtual disks offline. Use Failover Cluster Manager to take the Cluster Shared Volumes offline under \u0026lsquo;Storage \u0026gt; Disks\u0026rsquo; Or use Powershell to offline all disks with Get-ClusterSharedVolume -Cluster S2D-Cluster | Stop-ClusterResource Take the Cluster Pool offline Use Failover Cluster Manager to take the Cluster Pool offline under \u0026lsquo;Storage \u0026gt; Pools\u0026rsquo; Or use Powershell to offline the pool with Get-ClusterResource -Cluster S2D-Cluster | ?{$_.ResourceType -eq \u0026quot;Storage Pool\u0026quot;} | Stop-ClusterResource Stop the cluster. Run the Stop-Cluster -Cluster S2D-Cluster command Or use Failover Cluster Manager to stop the cluster. Disable the cluster service on each node. This prevents the cluster service from starting up while being patched. Set Cluster Service to Disabled in services.msc Or use Get-Service clussvc -ComputerName Server01 | Set-Service -StartupType Disabled Apply the Windows Server Cumulative Update and any required Servicing Stack Updates to all nodes. (You can update all nodes at the same time, no need to wait since the cluster is down). Restart the nodes, and ensure everything looks good. Set the cluster service back to Automatic on each node. Set the Cluster Service to Automatic in services.msc Or use Get-Service clussvc -ComputerName 'Server01' | Set-Service -StartupType Automatic Start the cluster. Run Start-Cluster -Name S2D-Cluster Bring the Cluster Pool back online. Use Failover Cluster Manager to bring the Cluster Pool online under \u0026lsquo;Storage \u0026gt; Pools\u0026rsquo; Or use Powershell to offline the pool with Get-ClusterResource -Cluster S2D-Cluster | ?{$_.ResourceType -eq \u0026quot;Storage Pool\u0026quot;} | Start-ClusterResource Bring the virtual disks back online. Use Failover Cluster Manager to bring the Cluster Shared Volumes online under \u0026lsquo;Storage \u0026gt; Disks\u0026rsquo; Or use Powershell to online all disks with Get-ClusterSharedVolume -Cluster S2D-Cluster | Start-ClusterResource Monitor the status of the virtual disks by running the Get-Volume and Get-VirtualDisk cmdlets. Simplifying the process # Seeing as this is a 13 step process, it\u0026rsquo;s 13 times human error can occur. To help with removing human error, and because I love automating things with Powershell, I\u0026rsquo;ve created some scripts to reduce the number of steps down to just 7.\nNow stopping the cluster once your VMs are offline is a single command - Stop-S2DCluster.\nStop-S2DCluster will check all your volumes are healthy, and all VMs are shut down before taking any action. It will then stop all CSVs, and the Storage Pool, before stopping the cluster and setting all the cluster services to disabled on the hosts.\nStarting things up after you\u0026rsquo;ve patched all the hosts is just as easy with Start-S2DCluster.\nUnlike Stop-S2DCluster, Start-S2DCluster needs to be run against a cluster node, rather than the cluster, as it will start the cluster service on that node first, and then automatically discover all the other nodes in the cluster. It\u0026rsquo;ll set all the cluster services back to automatic and start them. After the nodes have joined the cluster, it will bring the storage pool and CSVs back online.\n# Arrange a maintenance window for the outage ... # Stop the VMs Get-VM -ComputerName (Get-ClusterNode -Cluster S2D-Cluster).Name | Stop-VM # Shutdown the S2D Cluster Stop-S2DCluster -Name S2D-Cluster # Patch Hosts and Reboot ... # Start the S2D Cluster Start-S2DCluster -ComputerName S2DHost01 # Start the VMs Get-VM -ComputerName (Get-ClusterNode -Cluster S2D-Cluster).Name | Start-VM These Powershell commands are part of my S2D-Maintenance functions, and the latest version can be downloaded from by GitHub repo.\n# Download location $FileLocation = C:\\Scripts\\S2D-Maintenance.ps1 # Download link $URL = \u0026#34;https://github.com/comnam90/bcthomas.com-scripts/raw/master/Powershell/Functions/S2D-Maintenance.ps1\u0026#34; # Download the file [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 Invoke-WebRequest -UseBasicParsing -OutFile $FileLocation # Import Functions for use . $FileLocation Wrapping up # So in Part 1, we\u0026rsquo;ve gone over the process for performing offline maintenance to a Storage Spaces Direct or AzureStack HCI Cluster and automated a number of the steps to simplify the process.\nOffline maintenance is always advised when your cluster is 6 months or more behind on patching, as it reduces the risk of hitting known bugs and the window required to catch up to date on patches.\nNext time we\u0026rsquo;ll cover off using Cluster Aware Updating to make sure you don\u0026rsquo;t fall behind in patch level in the first place.\nOriginal Code # Function Stop-S2DCluster { \u0026lt;# .Synopsis Used to shutdown an S2D Cluster for Maintenance. .Description This command can be used to completely shutdown an S2D Cluster before performing offline maintenance. It can be run against multiple clusters remotely. The command will confirm shutting down each component by default but this can be skipped by using -Confirm:$false .Parameter Name The target cluster name that you want to shutdown. .Parameter SkipVirtualDiskCheck When the command executes, it will make sure all volumes are online and healthy before shutting anything down. This switch can be used to skip these checks if you know things are unhealthy and need to shutdown anyway. #\u0026gt; [cmdletbinding(SupportsShouldProcess, ConfirmImpact = \u0026#39;High\u0026#39;)] param( [parameter(Mandatory)] [alias(\u0026#39;Cluster\u0026#39;)] [string[]]$Name, [switch]$SkipVirtualDiskCheck ) begin { $results = @() } process { Foreach ($Cluster in $Name) { try { Write-Verbose \u0026#34;$Cluster - Gathering required information\u0026#34; $ClusterResources = Get-ClusterResource -Cluster $Cluster $ClusterPool = $ClusterResources | where-object { $_.ResourceType -eq \u0026#34;Storage Pool\u0026#34; } $CSVs = Get-ClusterSharedVolume -Cluster $Cluster $ClusterNodes = Get-ClusterNode -Cluster $Cluster $VirtualDisks = Get-VirtualDisk -CimSession $Cluster # Check Virtual Disks are healthy before shutting down Write-Verbose \u0026#34;$Cluster - Checking for unhealthy volumes\u0026#34; $UnhealthyDisks = $VirtualDisks | Where-Object { $_.HealthStatus -ine \u0026#34;Healthy\u0026#34; -and $_.OperationalStatus -ine \u0026#34;OK\u0026#34; } if ($UnhealthyDisks.Count -gt 0 -and $SkipVirtualDiskCheck) { Write-Warning \u0026#34;There are $($UnhealthyDisks.Count) unhealthy volumes on $Cluster\u0026#34; } elseif ($UnhealthyDisks.Count -gt 0) { Throw \u0026#34;$Cluster has $($UnhealthyDisks.Count) unhealthy disks.`nResolve issues with volume health before continuing`nor use -SkipVirtualDiskCheck and try again.\u0026#34; } # Check there are no running VMs Write-Verbose \u0026#34;$Cluster - Checking for running VMs\u0026#34; $RunningVMs = $ClusterResources | Where-Object { $_.ResourceType -eq \u0026#34;Virtual Machine\u0026#34; -and $_.State -eq \u0026#34;Online\u0026#34; } if ($RunningVMs.Count -gt 0) { # Possibly use ShoudlProcess here instead to offer stopping VMs Throw \u0026#34;$Cluster cannot to shutdown because there are still running VMs`nVMs: $( ( $RunningVMs -join \u0026#34;, \u0026#34; ) )\u0026#34; } # Stop CSVs Write-Verbose \u0026#34;$Cluster - Starting shutdown proceedures\u0026#34; Foreach ($CSV in $CSVs) { if ($PSCmdlet.ShouldProcess( (\u0026#34;Stopping {0} on {1}\u0026#34; -f $CSV.Name, $Cluster), (\u0026#34;Would you like to stop {0} on {1}?\u0026#34; -f $CSV.Name, $Cluster), \u0026#34;Stop Cluster Shared Volume\u0026#34; ) ) { try { $CSV | Stop-ClusterResource -Cluster $Cluster -ErrorAction Stop | Out-Null } catch { Throw \u0026#34;Something went wrong when trying to stop $($CSV.Name)`nRerun the command.`n$($PSItem.ToString())\u0026#34; } } } # Stop Cluster Pool if ($PSCmdlet.ShouldProcess( (\u0026#34;Stopping {0} on {1}\u0026#34; -f $ClusterPool.Name, $Cluster), (\u0026#34;Would you like to stop {0} on {1}?\u0026#34; -f $ClusterPool.Name, $Cluster), \u0026#34;Stop Cluster Pool\u0026#34; ) ) { try { $ClusterPool | Stop-ClusterResource -Cluster $Cluster -ErrorAction Stop | Out-Null } catch { Throw \u0026#34;Something went wrong when trying to stop $($ClusterPool.Name)`nRerun the command.`n$($PSItem.ToString())\u0026#34; } } # Stop Cluster if ($PSCmdlet.ShouldProcess( (\u0026#34;Stopping {0}\u0026#34; -f $Cluster), (\u0026#34;Would you like to stop {0}?\u0026#34; -f $Cluster), \u0026#34;Stop Cluster\u0026#34; ) ) { try { # Stop Cluster Write-Verbose \u0026#34;$Cluster - Shutting down Cluster\u0026#34; Stop-Cluster -Cluster $Cluster -Force -Confirm:$false -ErrorAction Stop foreach ($Node in $ClusterNodes.Name) { $Service = Get-Service clussvc -ComputerName $Node # Stop Cluster Service on hosts Write-Verbose \u0026#34;$Cluster - $Node - Stopping Cluster Service\u0026#34; $Service | Stop-Service # Set Cluster Service to disabled on hosts Write-Verbose \u0026#34;$Cluster - $Node - Disabling Cluster Service Startup\u0026#34; $Service | Set-Service -StartupType Disabled } } catch { Throw \u0026#34;Something went wrong when trying to stop $($Cluster)`nRerun the command.`n$($PSItem.ToString())\u0026#34; } } } catch { Write-Warning \u0026#34;$($PSItem.ToString())\u0026#34; $results += [pscustomobject][ordered]@{ Name = $Cluster Result = \u0026#34;Failed\u0026#34; } continue } Write-Verbose \u0026#34;$Cluster - Writing results\u0026#34; $results += [pscustomobject][ordered]@{ Name = $Cluster Result = \u0026#34;Succeeded\u0026#34; } } } end { Write-Verbose \u0026#34;Returning results\u0026#34; $results } } Function Start-S2DCluster { \u0026lt;# .Synopsis Used to start an S2D Cluster after maintenance. .Description This command can be used to start up an S2D Cluster afte performing offline maintenance. It will run locally or remotely but only against a single target. .Parameter ComputerName The name of a host in the cluster you want to start. #\u0026gt; [cmdletbinding()] param( [alias(\u0026#39;ClusterNode\u0026#39;)] [string]$ComputerName = $Env:ComputerName ) begin { } process { try { # Force Cluster Online on single Node Write-Verbose \u0026#34;$ComputerName - Starting Cluster on a single node\u0026#34; $NodeSvc = Get-Service clussvc -ComputerName $ComputerName if ($NodeSvc.Status -eq \u0026#34;Running\u0026#34;) { Write-Verbose \u0026#34;$ComputerName - Cluster Service is already running\u0026#34; } else { Invoke-Command -ComputerName $ComputerName -ErrorAction Stop -ScriptBlock { Get-Service clussvc | Set-Service -StartupType Automatic net start clussvc /forcequorum } } # Get cluster information Write-Verbose \u0026#34;Gathering cluster information\u0026#34; # Sleep for 5sec to make sure cluster is online Start-Sleep -Seconds 5 $Cluster = Get-Cluster $ComputerName -ErrorAction Stop $ClusterName = $Cluster.Name $ClusterNodes = Get-ClusterNode -Cluster $ClusterName -ErrorAction Stop $ClusterPool = Get-ClusterResource -Cluster $ClusterName -ErrorAction Stop | Where-Object { $_.ResourceType -eq \u0026#34;Storage Pool\u0026#34; } $CSVs = Get-ClusterSharedVolume -Cluster $ClusterName -ErrorAction Stop # Start other Nodes Write-Verbose \u0026#34;$ClusterName - Starting Cluster Service on remaining Nodes\u0026#34; Foreach ( $Node in ($ClusterNodes | Where-Object { $_.State -eq \u0026#34;Down\u0026#34; }).Name ) { $Service = Get-Service clussvc -ComputerName $Node # Set to automatic start Write-Verbose \u0026#34;$ClusterName - $Node - Setting Cluster Service back to Automatic Startup\u0026#34; $Service | Set-Service -StartupType Automatic -ErrorAction Stop # Start Service Write-Verbose \u0026#34;$ClusterName - $Node - Starting Cluster Service\u0026#34; $Service | Start-Service -ErrorAction Stop } # Sleep for 5sec to make sure cluster nodes are online Write-Verbose \u0026#34;$ClusterName - Wait for Cluster Nodes to join\u0026#34; do { Start-Sleep -Seconds 5 $DownNodesCount = Get-ClusterNode -Cluster $ClusterName | Where-Object { $_.State -ne \u0026#39;Up\u0026#39; } | Measure-Object | Select-Object -ExpandProperty Count }until( $DownNodesCount -eq 0 ) # Start Pool Write-Verbose \u0026#34;$ClusterName - Starting Cluster Pool $($ClusterPool.Name)\u0026#34; $ClusterPool | Start-ClusterResource -ErrorAction Stop | Out-Null # Start CSVs Write-Verbose \u0026#34;$ClusterName - Starting Cluster Shared Volumes\u0026#34; $CSVs | Start-ClusterResource -ErrorAction Stop | Out-Null } catch { throw \u0026#34;Something went wrong when trying to start the cluster back up`n$($PSItem.ToString())\u0026#34; } } end { \u0026#34;Successfully started cluster on $ComputerName\u0026#34; } } ","date":"1 June 2019","externalUrl":null,"permalink":"/2019/06/best-practices-for-patching-s2d-and-azurestack-hci-clusters-part-1/","section":"Posts","summary":"Patching S2D clusters is a common question. This first part covers offline patching—shutting everything down, patching all nodes simultaneously, and starting back up—with scripts like Stop-S2DCluster and Start-S2DCluster to automate the process.","title":"Best Practices for patching S2D and AzureStack HCI Clusters - Part 1","type":"posts"},{"content":"","date":"1 June 2019","externalUrl":null,"permalink":"/tags/cau/","section":"Tags","summary":"","title":"CAU","type":"tags"},{"content":"","date":"1 June 2019","externalUrl":null,"permalink":"/tags/cluster-aware-updating/","section":"Tags","summary":"","title":"Cluster Aware Updating","type":"tags"},{"content":"","date":"1 June 2019","externalUrl":null,"permalink":"/tags/patching/","section":"Tags","summary":"","title":"Patching","type":"tags"},{"content":"","date":"25 May 2019","externalUrl":null,"permalink":"/tags/maintenance/","section":"Tags","summary":"","title":"Maintenance","type":"tags"},{"content":"Storage Spaces Direct (S2D) is an incredibly powerful technology, and makes up a huge part of the new AzureStack HCI Solution, however performing maintenance on it can catch out new players.\nOne of the biggest causes of failures while performing maintenance on S2D hosts and clusters, is that the hosts haven\u0026rsquo;t been correctly put into maintenance mode, so I set out to simplify the process with 3 new functions.\nThe 3 activities I\u0026rsquo;ve targeted with these functions are enabling and disabling maintenance mode on a host correctly, and checking the current state of a host or cluster.\nWith all maintenance, it\u0026rsquo;s a good idea to make sure the cluster is healthy before starting, and that the host you\u0026rsquo;re going to make changes to is actually in maintenance mode.\nTo assist with this, I\u0026rsquo;ve created Get-S2DNodeMaintenanceState. It can be used to query one or more hosts, as well as one or more clusters at a time.\n# Query the local host Get-S2DNodeMaintenanceState # Query a single host Get-S2DNodeMaintenanceState -Name S2DHost01 # Query multiple hosts Get-S2DNodeMaintenanceState -Name \u0026#39;S2DHost01\u0026#39;,\u0026#39;S2DHost02\u0026#39; # Query the state of all hosts in a cluster Get-S2DNodeMaintenanceState -Cluster S2D-Cluster Next, I have created a function to put a host into maintenance mode, which by default will follow best practice and pause the cluster node, and then put the host\u0026rsquo;s disks into storage maintenance mode.\nThis function is called Enable-S2DNodeMaintenance and is designed to be run against a single host at a time.\n# Enable maintenance mode on the local host Enable-S2DNodeMaintenance # Enable maintenance mode on a remote host Enable-S2DNodeMaintenance -Name S2DHost01 # Pause a host\u0026#39;s cluster service but not it\u0026#39;s storage Enable-S2DNodeMaintenance -OnlyCluster # Put a host\u0026#39;s disks into Storage maintenance mode Enable-S2DNodeMaintenance -OnlyStorage The final action when performing maintenance is to bring a host out of maintenance mode, so we have Disable-S2DNodeMaintenance for that.\nLike Enable-S2DNodeMaintenance, Disable-S2DNodeMaintenance is designed to be run against a single host at a time.\n# Disable maintenance mode on the local host Disable-S2DNodeMaintenance # Disable maintenance mode on a remote host Disable-S2DNodeMaintenance -Name S2DHost01 # Resume a host\u0026#39;s cluster service but not it\u0026#39;s storage Disable-S2DNodeMaintenance -OnlyCluster # Bring a host\u0026#39;s disks out of Storage maintenance mode Disable-S2DNodeMaintenance -OnlyStorage All of these new functions have been uploaded to Github to make it easier for me to maintain them going forwards and can be located here.\nTo get these into your environment, the below script will help you download the latest version of the functions and import them.\n# Download location $FileLocation = \u0026#39;C:\\Scripts\\S2D-Maintenance.ps1\u0026#39; # Download link $URL = \u0026#34;https://raw.githubusercontent.com/comnam90/bcthomas.com-scripts/master/Powershell/Functions/S2D-Maintenance.ps1\u0026#34; # Download the file [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 Invoke-WebRequest -Uri $URL -UseBasicParsing -OutFile $FileLocation # Import Functions for use . $FileLocation So now hopefully everyone has a much easier way of ensuring that their hosts are correctly in maintenance mode when they need it.\nUpdate (2019-05-26):\nAdditional commands have been added to the S2D-Maintenance.ps1 script since this article was initially posted. These commands will be explained in a follow-up blog series on best practices for patching S2D and AzureStack HCI Clusters.\nOriginal Code # Function Enable-S2DNodeMaintenance { [cmdletbinding()] Param( [alias(\u0026#39;ComputerName\u0026#39;, \u0026#39;StorageNodeFriendlyName\u0026#39;)] [string]$Name = $Env:ComputerName, [switch]$OnlyCluster, [switch]$OnlyStorage ) begin { Write-Verbose \u0026#34;Checking that the required powershell modules are available\u0026#34; $AvailableModules = Get-Module -ListAvailable -Verbose:$false if ( $AvailableModules.Name -inotcontains \u0026#34;FailoverClusters\u0026#34; -or $AvailableModules.Name -inotcontains \u0026#34;Storage\u0026#34; ) { throw \u0026#34;Required modules FailoverClusters and Storage are not available\u0026#34; } } process { Write-Verbose \u0026#34;Checking that all volumes are currently healthy before enabling maintenance\u0026#34; $UnhealthyDisks = Get-VirtualDisk -CimSession $Name | Where-Object { $_.HealthStatus -ine \u0026#34;Healthy\u0026#34; -and $_.OperationalStatus -ine \u0026#34;OK\u0026#34; } if ($UnhealthyDisks.Count -gt 0) { throw \u0026#34;Cannot enter maintenance mode as the follow volumes are unhealthy`n$($UnhealthyDisks.FriendlyName -join \u0026#34;, \u0026#34;)\u0026#34; } if ( -not $OnlyStorage ) { Write-Verbose \u0026#34;Pausing and draining $Name\u0026#34; $ClusterName = Get-Cluster -Name $Name | Select-Object -ExpandProperty Name $NodeState = (Get-ClusterNode -Name $Name -Cluster $ClusterName).State if ( $NodeState -ieq \u0026#39;Up\u0026#39; ) { Suspend-ClusterNode -Name $Name -Drain -Cluster $ClusterName -Wait | Out-Null } elseif ($NodeState -ieq \u0026#39;Paused\u0026#39;) { Write-Verbose \u0026#34;Skipping $Name as it is already paused\u0026#34; } else { Write-Warning \u0026#34;$Name is currently $NodeState\u0026#34; } } if ( -not $OnlyCluster ) { Write-Verbose \u0026#34;Enabling Storage Maintenance Mode on disks in $Name\u0026#34; $ScaleUnit = Get-StorageFaultDomain -Type StorageScaleUnit -CimSession $Name | Where-Object { $_.FriendlyName -eq $Name } $ScaleUnit | Enable-StorageMaintenanceMode -CimSession $Name | Out-Null Start-Sleep -Seconds 5 } } end { Write-Verbose \u0026#34;Returning current state of host\u0026#34; Get-S2DNodeMaintenanceState -Name $Name } } Function Disable-S2DNodeMaintenance { [cmdletbinding()] Param( [alias(\u0026#39;ComputerName\u0026#39;, \u0026#39;StorageNodeFriendlyName\u0026#39;)] [string]$Name = $Env:ComputerName, [switch]$OnlyCluster, [switch]$OnlyStorage ) begin { Write-Verbose \u0026#34;Checking that the required powershell modules are available\u0026#34; $AvailableModules = Get-Module -ListAvailable -Verbose:$false if ( $AvailableModules.Name -inotcontains \u0026#34;FailoverClusters\u0026#34; -or $AvailableModules.Name -inotcontains \u0026#34;Storage\u0026#34; ) { throw \u0026#34;Required modules FailoverClusters and Storage are not available\u0026#34; } } process { if ( -not $OnlyCluster ) { Write-Verbose \u0026#34;Disabling Storage Maintenance Mode on disks in $Name\u0026#34; $ScaleUnit = Get-StorageFaultDomain -Type StorageScaleUnit -CimSession $Name | Where-Object { $_.FriendlyName -eq $Name } $ScaleUnit | Disable-StorageMaintenanceMode -CimSession $Name | Out-Null Start-Sleep -Seconds 5 } if ( -not $OnlyStorage ) { Write-Verbose \u0026#34;Resuming $Name and moving roles back\u0026#34; $ClusterName = Get-Cluster -Name $Name | Select-Object -ExpandProperty Name $NodeState = (Get-ClusterNode -Name $Name -Cluster $ClusterName).State if ( $NodeState -ieq \u0026#39;Paused\u0026#39; ) { Resume-ClusterNode -Name $Name -Failback Immediate -Cluster $ClusterName | Out-Null } elseif ($NodeState -ieq \u0026#34;Up\u0026#34;) { Write-Verbose \u0026#34;Skipping $Name as it is not currently paused\u0026#34; } else { Write-Warning \u0026#34;$Name is currently $NodeState\u0026#34; } } } end { Write-Verbose \u0026#34;Returning current state of $Name\u0026#34; Get-S2DNodeMaintenanceState -Name $Name } } Function Get-S2DNodeMaintenanceState { [cmdletbinding(DefaultParameterSetName = \u0026#34;Node\u0026#34;)] Param( [parameter(ParameterSetName = \u0026#34;Node\u0026#34;)] [alias(\u0026#39;ComputerName\u0026#39;)] [string[]]$Name = $Env:ComputerName, [parameter(ParameterSetName = \u0026#34;Cluster\u0026#34;)] [string[]]$Cluster ) begin { Write-Verbose \u0026#34;Checking that the required powershell modules are available\u0026#34; $AvailableModules = Get-Module -ListAvailable -Verbose:$false if ( $AvailableModules.Name -inotcontains \u0026#34;FailoverClusters\u0026#34; -or $AvailableModules.Name -inotcontains \u0026#34;Storage\u0026#34; ) { throw \u0026#34;Required modules FailoverClusters and Storage are not available\u0026#34; } if ($PSCmdlet.ParameterSetName -ieq \u0026#39;Cluster\u0026#39;) { Write-Verbose \u0026#34;Execution context: Cluster\u0026#34; Write-Verbose \u0026#34;Getting Node to Cluster mappings\u0026#34; $NodeMappings = @{ } $Name = foreach ($S2DCluster in $Cluster) { $Nodes = Get-ClusterNode -Cluster $S2DCluster | Select-Object -ExpandProperty Name Foreach ($Node in $Nodes) { Write-Verbose \u0026#34;$Node is part of $S2DCluster\u0026#34; $NodeMappings[$Node] = $S2DCluster } $Nodes } } $results = @() } process { Foreach ($ClusterNode in $Name) { Write-Verbose \u0026#34;$ClusterNode - Starting to gather state info\u0026#34; Write-Verbose \u0026#34;$ClusterNode - Gather physical disk details\u0026#34; $NodeDisks = Get-StorageSubSystem clu* -CimSession $ClusterNode | Get-StorageNode | Where-Object { $_.Name -ilike \u0026#34;*$ClusterNode*\u0026#34; } | Get-PhysicalDisk -PhysicallyConnected -CimSession $ClusterNode Write-Verbose \u0026#34;$ClusterNode - Gather Cluster Name\u0026#34; if ($PSCmdlet.ParameterSetName -ieq \u0026#39;Node\u0026#39;) { $ClusterName = Get-Cluster -Name $ClusterNode | Select-Object -ExpandProperty Name } else { $ClusterName = $NodeMappings[$ClusterNode] } Write-Verbose \u0026#34;$ClusterNode - Gather Cluster Node State\u0026#34; $ClusterNodeState = Get-ClusterNode -Name $ClusterNode -Cluster $ClusterName | Select-Object -ExpandProperty State Write-Verbose \u0026#34;$ClusterNode - Gather Storage Node State\u0026#34; $StorageNodeState = switch ($NodeDisks.Where( { $_.OperationalStatus -icontains \u0026#34;In Maintenance Mode\u0026#34; } ).Count) { 0 { \u0026#34;Up\u0026#34;; Break } { $_ -lt $NodeDisks.Count } { \u0026#34;PartialMaintenance\u0026#34;; Break } { $_ -eq $NodeDisks.Count } { \u0026#34;InMaintenance\u0026#34;; Break } default { \u0026#34;UNKNOWN\u0026#34; } } Write-Verbose \u0026#34;$ClusterNode - Compile results\u0026#34; $Results += [pscustomobject][ordered]@{ Cluster = $ClusterName Name = $ClusterNode ClusterState = $ClusterNodeState StorageState = $StorageNodeState } } } end { Write-Verbose \u0026#34;Return state details\u0026#34; $results } } ","date":"25 May 2019","externalUrl":null,"permalink":"/2019/05/perform-better-storage-spaces-direct-maintenance-with-these-powershell-functions/","section":"Posts","summary":"Improper maintenance mode is a top cause of S2D failures. These three PowerShell functions—Get-S2DNodeMaintenanceState, Enable-S2DNodeMaintenance, and Disable-S2DNodeMaintenance—make it easy to do it right.","title":"Perform better Storage Spaces Direct maintenance with these Powershell functions","type":"posts"},{"content":"","date":"20 May 2019","externalUrl":null,"permalink":"/tags/azure/","section":"Tags","summary":"","title":"Azure","type":"tags"},{"content":"","date":"20 May 2019","externalUrl":null,"permalink":"/tags/azure-monitor/","section":"Tags","summary":"","title":"Azure Monitor","type":"tags"},{"content":"After my previous article about the wonders of the new Azure Update Management Extension for SCVMM 2019, some of you might have been thinking that it was all well and good that VMM now automates the installation and configuration of the Azure Monitor Log Analytics Agent (MMA) for you when deploying new VMs, but what about all those existing servers out there?\nWell unfortunately out of the box, Microsoft doesn\u0026rsquo;t provide a single installer UI that can target multiple machines, unless you\u0026rsquo;ve also got SCOM deployed and have configured it\u0026rsquo;s OMS integration as well.\nNevertheless, Powershell is to the rescue! With a little bit of Googling, I was able to find a rather nice script created by John Savill, but it too was limited to being run interactively on a single machine at a time.\nSo I decided to take things into my own hands and craft a Powershell function that can target as many servers as I want, with some added flexibility as to whether I want to download a fresh installed or use an existing copy saved on a share.\nThe resulting script is a little long to read over, but it does the trick!\nfunction Install-OMSAgents { \u0026lt;# .Synopsis Used to install OMS Agents .Description Used to install OMS Agents locally and remotely. It will download the required installer by default, but you can also specify a path to the installer if you don\u0026#39;t have internet access for all machines you wish to install it on, or want to save bandwidth. .Parameter ComputerName Array of Computer Names to install the OMS agent on. .Parameter WorkspaceID Azure Log Analytics Workspace ID. .Parameter WorkspaceKey Azure Log Analytics Workspace Key. .Parameter OMSDownloadPath Specify the directory on each machine to download the installer to. .Parameter InstallerPath Specify a local or UNC path to the MMA installer if you don\u0026#39;t want to download it automatically. Requires all servers you want to be able to install the Agent on to have access to the share hosting the installer. .Parameter OverrideExisting Triggers overriding existing workspaces on machines with the agent already installed. .Example Install-OMSAgents -ComputerName Server01 -WorkspaceID xxxxxx -WorkspaceKey xxxxx This will default to downloading and installing the Microsoft Monitoring Agent on Server01 from the internet, and configure it to point to the specified Azure Log Analytics Workspace .Example Install-OMSAgents -ComputerName \u0026#39;Server01\u0026#39;,\u0026#39;Server02\u0026#39; -InstallerPath \\\\nas01\\share01\\MMASetup-AMD64.exe -WorkspaceID xxx -WorkspaceKey xxx This will install on Server01 and Server02 using the installer found on NAS01. .Notes Big shout out to John Savill (@ntfaqguy) for the original script I used to create this function, it can be found on his website https://savilltech.com/2018/01/21/deploying-the-oms-agent-automatically/ --------------------------------------------------------------- Version: 1.0.0 Maintained By: Ben Thomas (@NZ_BenThomas) Last Updated: 2019-05-20 --------------------------------------------------------------- CHANGELOG: 1.0.0 - Initial version - Updated @ntfaqguy\u0026#39;s script to a function - Added support for remotely running against multiple machines - Added parameters to specify a central installer rather than downloading the agent on every machine. - Added a switch for overridding existing Agent installs with new workspace details. .Link https://bcthomas.com #\u0026gt; [cmdletbinding(DefaultParameterSetName = \u0026#39;Download\u0026#39;)] param( [string[]]$ComputerName = \u0026#39;Localhost\u0026#39;, [parameter(Mandatory)] [string]$WorkspaceID, [parameter(Mandatory)] [string]$WorkspaceKey, [parameter(ParameterSetName = \u0026#39;Download\u0026#39;)] [string]$OMSDownloadPath = \u0026#39;C:\\Temp\u0026#39;, [parameter(Mandatory, ParameterSetName = \u0026#39;Offline\u0026#39;)] [string]$InstallerPath, [switch]$OverrideExisting ) begin { #region: Helper Functions function Get-InstalledSoftware { param( [string]$ComputerName = \u0026#39;localhost\u0026#39;, [string]$ProductName = \u0026#39;*\u0026#39; ) $UninstallKey = ”SOFTWARE\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Uninstall” $reg = [microsoft.win32.registrykey]::OpenRemoteBaseKey(‘LocalMachine’, $ComputerName) $regkey = $reg.OpenSubKey($UninstallKey) $subkeys = $regkey.GetSubKeyNames() foreach ($key in $subkeys) { $thisKey = $UninstallKey + ”\\\\” + $key $thisSubKey = $reg.OpenSubKey($thisKey) $DisplayName = $($thisSubKey.GetValue(“DisplayName”)) if ($DisplayName -ilike $ProductName) { [pscustomobject][ordered]@{ ComputerName = $ComputerName ProductName = $($thisSubKey.GetValue(“DisplayName”)) DisplayVersion = $($thisSubKey.GetValue(“DisplayVersion”)) InstallLocation = $($thisSubKey.GetValue(“InstallLocation”)) Publisher = $($thisSubKey.GetValue(“Publisher”)) } } } } #endregion Write-Verbose \u0026#34;Establish Sessions to target machines\u0026#34; $Sessions = @{ } $ExcludedComputers = @() $OverrideComputers = @() $Results = @() foreach ($Computer in $ComputerName) { try { $NewSession = New-PSSession -ComputerName $Computer -Name $Computer -ErrorAction Stop Write-verbose \u0026#34;Checking if OMS Agent is installed on $Computer\u0026#34; $MMAObj = Get-InstalledSoftware -ProductName \u0026#39;Microsoft Monitoring Agent\u0026#39; -ComputerName $Computer if ($MMAObj -and ( -not $OverrideExisting) ) { throw \u0026#34;Agent is already installed\u0026#34; } elseif ($MMAObj -and $OverrideExisting) { Write-Warning \u0026#34;Agent found on $Computer, the existing settings on this`nMachine will be overridden.\u0026#34; $OverrideComputers += $Computer } else { Write-Verbose \u0026#34;No Agent found, install scheduled.\u0026#34; } $Sessions.Add($Computer, $NewSession) } catch { Write-Warning \u0026#34;An error occured and $Computer will be excluded.`nError Details: $($PSItem.ToString())\u0026#34; $ExcludedComputers += $Computer Continue } } } Process { Foreach ($Computer in $ComputerName) { if ($Computer -iin $ExcludedComputers) { Write-Warning \u0026#34;Skipping $Computer as it\u0026#39;s excluded\u0026#34; } else { try { $Install = $true if ($Computer -iin $OverrideComputers) { $Install = $false } if ($PSCmdlet.ParameterSetName -eq \u0026#39;Download\u0026#39;) { # Download the required installer onto the remove machine Write-Verbose \u0026#34;Downloading MMASetup-AMD64.exe to $Computer $OMSDownloadPath\u0026#34; $InstallerPath = Invoke-Command -session $Sessions[$computer] ` -ArgumentList $OMSDownloadPath, $Install ` -ErrorAction Stop ` -ScriptBlock { param( $OMSDownloadPath, $Install ) $OMS64bitDownloadURL = \u0026#34;https://go.microsoft.com/fwlink/?LinkId=828603\u0026#34; $OMSDownloadFileName = \u0026#34;MMASetup-AMD64.exe\u0026#34; $OMSDownloadFullPath = \u0026#34;$OMSDownloadPath\\$OMSDownloadFileName\u0026#34; if ($Install) { #Create temporary folder if it does not exist if (-not (Test-Path -Path $OMSDownloadPath)) { New-Item -Path $OMSDownloadPath -ItemType Directory | Out-Null } Write-host \u0026#34;$env:computername - Downloading the agent...\u0026#34; #Download to the temporary folder Invoke-WebRequest -Uri $OMS64bitDownloadURL -OutFile $OMSDownloadFullPath | Out-Null } \u0026#34;$OMSDownloadFullPath\u0026#34; } } $Workspaces = Invoke-Command -Session $Sessions[$Computer] ` -ArgumentList $InstallerPath, $WorkspaceID, $WorkspaceKey, $OverrideExisting, $Install ` -ErrorAction Stop ` -ScriptBlock { Param( $InstallerPath, $WorkspaceID, $WorkspaceKey, $OverrideExisting, $Install ) Write-host \u0026#34;$env:computername - Installing the agent...\u0026#34; if ((-Not (Test-Path -Path $InstallerPath)) -and $Install ) { throw \u0026#34;$ComputerName cannot access $InstallerPath\u0026#34; } elseif ($Install) { #Install the agent $ArgumentList = \u0026#39;/C:\u0026#34;setup.exe /qn ADD_OPINSIGHTS_WORKSPACE=0 AcceptEndUserLicenseAgreement=1\u0026#34;\u0026#39; Start-Process $InstallerPath -ArgumentList $ArgumentList -ErrorAction Stop -Wait | Out-Null } #Check if the CSE workspace is already configured $AgentCfg = New-Object -ComObject AgentConfigManager.MgmtSvcCfg $OMSWorkspaces = $AgentCfg.GetCloudWorkspaces() $CSEWorkspaceFound = $false foreach ($OMSWorkspace in $OMSWorkspaces) { if ($OMSWorkspace.workspaceId -eq $WorkspaceID) { $CSEWorkspaceFound = $true } elseif ($OverrideExisting) { $AgentCfg.RemoveCloudWorkspace($OMSWorkspace.workspaceId) $AgentCfg.ReloadConfiguration() } } if (!$CSEWorkspaceFound) { Write-host \u0026#34;$env:computername - Adding CSE OMS Workspace...\u0026#34; $AgentCfg.AddCloudWorkspace($WorkspaceID, $WorkspaceKey) Restart-Service HealthService } else { Write-Warning \u0026#34;CSE OMS Workspace already configured\u0026#34; } # Get all configured OMS Workspaces sleep 5 $AgentCfg.GetCloudWorkspaces() } $Results += [pscustomobject][ordered]@{ ComputerName = $Computer AgentID = $Workspaces.AgentID WorkspaceID = $Workspaces.WorkspaceID Status = $Workspaces.ConnectionStatusText } } catch { Write-Warning \u0026#34;Installation failed on $Computer`nRan into an issue: $($PSItem.ToString())\u0026#34; Continue } } } } End { foreach ($connection in $Sessions.Keys) { $Sessions[$connection] | Remove-PSSession -Confirm:$false } $Results } } I will continue to maintain the function in my Github repo, however, this initial cut should get others going!\nHopefully, this helps you accelerate your adoption of some of the great Azure Hybrid scenarios available today.\n","date":"20 May 2019","externalUrl":null,"permalink":"/2019/05/installing-azure-monitor-log-analytics-agents-with-powershell/","section":"Posts","summary":"Need to deploy the Azure Monitor Log Analytics agent to existing servers? This PowerShell function handles single or multi-server deployments, with options to download the installer or use a central share.","title":"Installing Azure Monitor Log Analytics Agents with Powershell","type":"posts"},{"content":"","date":"20 May 2019","externalUrl":null,"permalink":"/tags/log-analytics/","section":"Tags","summary":"","title":"Log Analytics","type":"tags"},{"content":"","date":"20 May 2019","externalUrl":null,"permalink":"/tags/log-insights/","section":"Tags","summary":"","title":"Log Insights","type":"tags"},{"content":"","date":"20 May 2019","externalUrl":null,"permalink":"/tags/microsoft-monitoring-agent/","section":"Tags","summary":"","title":"Microsoft Monitoring Agent","type":"tags"},{"content":"","date":"20 May 2019","externalUrl":null,"permalink":"/tags/mma/","section":"Tags","summary":"","title":"MMA","type":"tags"},{"content":"","date":"20 May 2019","externalUrl":null,"permalink":"/tags/oms/","section":"Tags","summary":"","title":"OMS","type":"tags"},{"content":"","date":"14 May 2019","externalUrl":null,"permalink":"/tags/scvmm/","section":"Tags","summary":"","title":"SCVMM","type":"tags"},{"content":"Microsoft products are showing a clear theme these days, and the System Center Suite is no acception, hybrid scenarios and cloud augmentation.\nAnd while there are those that see this as just a way to drive Azure adoption, this doesn\u0026rsquo;t need to be a bad thing.\nIn this article, I\u0026rsquo;m going to cover how to take advantage of Azure Update Management, using the new Extension in System Center Virtual Machine Manager 2019.\nNote: For the purpose of this article, I will be assuming that VMM 2019 is already in place, as is an Azure Automation account with Update Management enabled.\nOne thing you might have noticed that\u0026rsquo;s new in the SCVMM 2019 console, is the \u0026lsquo;Azure Profiles\u0026rsquo; under the Library tab. Currently this allows for 2 kinds of Azure Profiles, \u0026lsquo;Azure VM Management\u0026rsquo; and \u0026lsquo;Azure Update Management\u0026rsquo;, but today we\u0026rsquo;re only interested in the later option, so let\u0026rsquo;s go ahead and create a new profile.\nThe first step of the wizard is a simple one, give the profile a descriptive name and provide the Azure Subscription ID, then select \u0026lsquo;Azure Update Management\u0026rsquo; as a Profile Usage.\nNow you need to provide the specific details for your Update Management environment in Azure, these can all be found in the Azure Portal.\nIf you\u0026rsquo;re like me, you prefer to use Powershell and avoid all those mouse clicks, so here\u0026rsquo;s the exact same steps without using the VMM Console.\n$NewSCAzureProfileParams = @{ Name = \u0026#34;Demo Azure Update Management\u0026#34; Description = \u0026#34;Showing off Azure Hybrid Integration for SCVMM2019 on bcthomas.com\u0026#34; SubscriptionId = \u0026#34;86b3aced-x00x-xx11-22xx-f9607460ffc5\u0026#34; CloudProvider = \u0026#34;AzurePublic\u0026#34; WorkspaceId = \u0026#34;ec9a0df0-3x3x-x4x4-5xx5-b4aac48f82c9\u0026#34; WorkspaceKey = \u0026#34;489Dos52PFOFBt0fZmoS91zZ78Ru7+xxxxx+xxxxxneLxxxxxpgjSJ+dpegWuxxxxHlAGRkNwxaXqB7GITgeg==\u0026#34; AutomationAccount = \u0026#34;SCVMM-Automation\u0026#34; AutomationAccountResourceGroup = \u0026#34;rg-blog-SCVMM\u0026#34; VMMServer = \u0026#34;SCVMM01\u0026#34; } New-SCAzureProfile @NewSCAzureProfileParams With the new Azure Profile configured, you can now make use of it as part of a standard VM deployment wizard. If you\u0026rsquo;ve configured multiple profile, you\u0026rsquo;ll be able to pick the appropriate one at deployment.\nOnce the VM deployment is finished, you\u0026rsquo;ll get a new detail section in the VM details pane called \u0026lsquo;Azure Update Management Info\u0026rsquo; with a hardlink button \u0026lsquo;Update Status\u0026rsquo; that will take you through to the Azure Portal again to show the status of the VM OS in Azure Update Management\nThis is all well and good for a quick start, but the real power is when you add the Azure Update Profile into your VM Templates. Now you can make sure all VM deployments will be onboarded into your Azure Update Management account, for an overview of the status of your VMs patch status and scheduling update remediation.\nI hope this helps someone get up and running with this new, simple but excellent SCVMM 2019 feature.\n","date":"14 May 2019","externalUrl":null,"permalink":"/2019/05/scvmm-2019-quick-start-guide-for-azure-update-management-extension/","section":"Posts","summary":"SCVMM 2019 introduces Azure Profiles for hybrid cloud integration. This guide shows how to create an Azure Update Management profile and automatically onboard VMs for patch status monitoring and remediation.","title":"SCVMM 2019 - Quick Start Guide for Azure Update Management Extension","type":"posts"},{"content":"","date":"14 May 2019","externalUrl":null,"permalink":"/tags/scvmm2019/","section":"Tags","summary":"","title":"SCVMM2019","type":"tags"},{"content":"","date":"14 May 2019","externalUrl":null,"permalink":"/categories/system-center/","section":"Categories","summary":"","title":"System Center","type":"categories"},{"content":"","date":"14 May 2019","externalUrl":null,"permalink":"/tags/updatemanagement/","section":"Tags","summary":"","title":"UpdateManagement","type":"tags"},{"content":"","date":"14 May 2019","externalUrl":null,"permalink":"/categories/virtual-machine-manager/","section":"Categories","summary":"","title":"Virtual Machine Manager","type":"categories"},{"content":"","date":"11 February 2019","externalUrl":null,"permalink":"/categories/containers/","section":"Categories","summary":"","title":"Containers","type":"categories"},{"content":"","date":"11 February 2019","externalUrl":null,"permalink":"/tags/containers/","section":"Tags","summary":"","title":"Containers","type":"tags"},{"content":"","date":"11 February 2019","externalUrl":null,"permalink":"/tags/docker/","section":"Tags","summary":"","title":"Docker","type":"tags"},{"content":"","date":"11 February 2019","externalUrl":null,"permalink":"/categories/general/","section":"Categories","summary":"","title":"General","type":"categories"},{"content":"As some of you would have seen, I spent some time last week getting familiar with Linux Containers on Windows Server 2019, and I thought I would share what I did to get it all up and running.\nPrerequisites # To get started, you\u0026rsquo;ll need to have the following in place:\nA Windows Server 2019 VM or Bare Metal host (VM-Only) Nested Virtualization enabled (VM-Only) MAC Address Spoofing enabled Hyper-V and Container Windows Features Enabled. You can install these from command line with Install-WindowsFeature -Name Hyper-V,Containers -IncludeAllSubFeature -IncludeManagementTools Install Docker EE # Installing Docker involves 2 steps, installing the Package Provider that contains the latest version of Docker, and installing the Docker Package.\nInstalling the Package Provider is straight forward\nInstall-Module DockerMSFTProvider Once that\u0026rsquo;s in place, we need to import the new module and the associated package provide\nImport-Module -Name DockerMSFTProvider -Force Import-Packageprovider -Name DockerMSFTProvider -Force We can confirm this has worked by using Find-Package to see the new docker package is available\nPS C:\\\u0026gt; Find-Package docker ################################ # Expected Output ################################ Name Version Source Summary ---- ------- ------ ------- Docker 18.09.1 DockerDefault Contains Docker EE for use with Windows Server. Docker 1.3.2 PSGallery This module helps with development using Doc... Now all that is left is to install Docker itself\nInstall-Package -Name Docker -Source DockerDefault Enable Linux Container Support # Now that we have Docker installed, we need to make some changes to the default configuration to enable support for Linux Containers.\nThis involves setting an Environment variable and creating a docker daemon configuration file.\n# Set LCOW_SUPPORTED Variable to 1 for enabled [Environment]::SetEnvironmentVariable(\u0026#34;LCOW_SUPPORTED\u0026#34;, \u0026#34;1\u0026#34;, \u0026#34;Machine\u0026#34;) # Enable Experimental Features in Dockerd daemon.conf $configfile = @\u0026#34; { \u0026#34;experimental\u0026#34;: true } \u0026#34;@ $configfile | Out-File -FilePath C:\\ProgramData\\docker\\config\\daemon.json -Encoding ascii -Force Because Linux Containers still need a Linux kernel, we need to deploy LCOW for it to run.\nYou should use the latest LCOW release here\nInvoke-WebRequest -Uri \u0026#34;https://github.com/linuxkit/lcow/releases/download/v4.14.35-v0.3.9/release.zip\u0026#34; -UseBasicParsing -OutFile release.zip Expand-Archive release.zip -DestinationPath \u0026#34;$Env:ProgramFiles\\Linux Containers\\.\u0026#34; And all that\u0026rsquo;s left to do now is restart the server for everything to apply.\nDeploy a Linux Container # You may be wondering why I\u0026rsquo;ve got a section for actually deploying a container, as surely it will \u0026lsquo;just work\u0026rsquo; now everything is setup, and that\u0026rsquo;s true, but because we now can deploy either Windows or Linux containers, we need to specify which we want.\nThis is done with an additional switch, --platform\nPersonally I like to use ubuntu as a quick test container\ndocker run --rm -it --platform=linux ubuntu bash Now if you\u0026rsquo;re like me and planning on deploying mostly Linux Containers, you probably don\u0026rsquo;t want to specify the --platform parameter every time you start a container.\nLuckily the default platform can be changes to Linux with another Environment variable.\n[Environment]::SetEnvironmentVariable(\u0026#34;LCOW_API_PLATFORM_IF_OMITTED\u0026#34;, \u0026#34;linux\u0026#34;, \u0026#34;Machine\u0026#34;) (Optional) Install Docker Compose # Now if you\u0026rsquo;ve been dealing with Docker on Linux for a while, you\u0026rsquo;ll probably be used to using Docker-Compose. Good news is it\u0026rsquo;s available for Windows Server as well, and is just as easy to deploy.\n$dockerComposeVersion = \u0026#34;1.23.2\u0026#34; Invoke-WebRequest \u0026#34;https://github.com/docker/compose/releases/download/$dockerComposeVersion/docker-compose-Windows-x86_64.exe\u0026#34; -UseBasicParsing -OutFile $Env:ProgramFiles\\docker\\docker-compose.exe (Optional) Enable Remote Management of Docker Engine # To enable access to the docker engine from other machines, such as your local workstation or a portainer deployment, we need to add a hosts entry to the Dockerd daemon.json file.\nIn our setup, we can do this with an easy find and replace.\n# New host entry to add $RemoteAccess = @\u0026#34; { \u0026#34;hosts\u0026#34;: [\u0026#34;tcp://0.0.0.0:2375\u0026#34;, \u0026#34;npipe://\u0026#34;], \u0026#34;@ # Get Existing Config $Config = Get-content C:\\ProgramData\\docker\\config\\daemon.json # Insert our host entry into the beginning of the file and write the changes back. $Config.Replace(\u0026#34;{\u0026#34;,$RemoteAccess)|Out-File -FilePath C:\\ProgramData\\docker\\config\\daemon.json -Encoding ascii -Force # Restart the docker service to apply the changes Restart-Service Docker As always, I hope this was helpful to someone else out there looking to experiment with the latest and greatest from Microsoft.\n","date":"11 February 2019","externalUrl":null,"permalink":"/2019/02/getting-started-with-linux-containers-on-windows-server-2019/","section":"Posts","summary":"Run Linux containers natively on Windows Server 2019! This guide covers installing Docker EE, enabling LCOW support, deploying the LinuxKit kernel, and running your first Linux container with the --platform switch.","title":"Getting started with Linux Containers on Windows Server 2019","type":"posts"},{"content":"","date":"11 February 2019","externalUrl":null,"permalink":"/tags/lcow/","section":"Tags","summary":"","title":"LCOW","type":"tags"},{"content":"","date":"11 February 2019","externalUrl":null,"permalink":"/tags/linux/","section":"Tags","summary":"","title":"Linux","type":"tags"},{"content":"One of the handy functions built into Powershell, is the ability to preview what would happen if you run a command. This could be as simple as wanting to make sure that your Remove-Item actually deletes the write files, or that Set-ADUser changes the right attribute.\nHand in hand with -WhatIf is -Confirm, it will prompt you for high risk actions and confirm if you really want to perform the action, like deleting an AD user account.\nBut what about when you\u0026rsquo;re writing your own Powershell function or script? How do you make sure people that use it can check it does what they want without actually making any changes? Or how do you make sure they really want to make that impacting change?\nThis was something that came up recently while working with Darryl van der Peijl on some code for a script he\u0026rsquo;s creating, and he suggested share the knowledge in a blog post, so here goes!\nI\u0026rsquo;m going start by making the assumption that if you\u0026rsquo;re here considering -WhatIf and -Confirm then you\u0026rsquo;ve already got a handle on the basics of creating a function.\nSo here is our example function that we\u0026rsquo;ll be working with, it performs 2 basic tasks, checks to see if a file already and creates or overwrites the file depending on the result.\nFunction New-PSFile { [CmdletBinding()] Param( # File to Create [Parameter(Mandatory=$true)] [string] $FilePath ) begin{ Write-Verbose \u0026#34;Checking to see if the file provided already exists\u0026#34; $FileExists = Test-Path -Path $FilePath } process{ try { if ($FileExists){ Write-Warning \u0026#34;$FilePath already exists and will be overwritten\u0026#34; $File = New-Item -Path $FilePath -ItemType File -Force -ErrorAction Stop } else{ Write-Verbose \u0026#34;Creating $FilePath\u0026#34; $File = New-Item -Path $FilePath -ItemType File -Force -ErrorAction Stop } } catch{ Throw \u0026#34;$($_.Exception.Message)\u0026#34; } } end{ Write-Verbose \u0026#34;Returning new file details\u0026#34; Return $File } } Now this example function is already got things like verbose output, warnings and a check to see if the file we\u0026rsquo;re targeting already exists, but in it\u0026rsquo;s currently state it\u0026rsquo;ll only throw up a warning about needing to overwrite the file, and then do it anyway, and we have no way to give this a dry run first to see what it will do.\nTo get started, we\u0026rsquo;ll add SupportsShouldProcess to our [CmbletBinding()] arguments, as this will enable the use of ShouldProcess() blocks.\nFunction New-PSFile { [CmdletBinding(SupportsShouldProcess=$true)] Param( # File to Create [Parameter(Mandatory=$true)] [string] $FilePath ) begin{ ... } process{ ... } end{ ... } } While we\u0026rsquo;ve now enabled the -WhatIf Parameter, it isn\u0026rsquo;t actually able to do anything at the moment if you tried to run it.\nTo actually put it into action, we need to add a ShouldProcess() block into our function where we want the WhatIf to actually run.\nThis block is if implemented in an If() statement around the action that you want to skip in a dry run, and is part of the $PSCmdlet variable.\nFor a basic implementation, we can supply just 2 arguments into this block, the Target object and the Action being performed.\n20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 process{ try { if ($FileExists){ ... } else{ Write-Verbose \u0026#34;Creating $FilePath\u0026#34; if($PSCmdlet.ShouldProcess($FilePath,\u0026#34;Create File\u0026#34;)){ $File = New-Item -Path $FilePath -ItemType File -Force -ErrorAction Stop } } } catch{ Throw \u0026#34;$($_.Exception.Message)\u0026#34; } } Now we\u0026rsquo;ve got a way to perform a dry run of our function, but how do we prevent people from accidentally overwriting important files? Well this is where the -Confirm parameter comes in handy. If your function or script is potentially impacting, you might want to change the ConfirmImpact level to High to force a user prompt when running it.\nLike with adding the SupportsShouldProcess, we add need to add ConfirmImpact to our [CmdletBinding()].\nFunction New-PSFile { [CmdletBinding(SupportsShouldProcess=$true,ConfirmImpact=\u0026#39;High\u0026#39;)] Param( # File to Create [Parameter(Mandatory=$true)] [string] $FilePath ) begin{ ... } process{ ... } end{ ... } } Now things are coming together!\nLet\u0026rsquo;s go one step further and make our WhatIf and Confirm strings more natural and custom for when we\u0026rsquo;re overwriting an existing file, to provide more context to the end user.\nTo do this, we will change our ShouldProcess() this time to have 3 arguments:\nThe message presented to the user when they run -WhatIf The message presented to the user asking for confirmation The confirmation prompt title 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 process{ try { if ($FileExists){ Write-Warning \u0026#34;$FilePath already exists and will be overwritten\u0026#34; if($PSCmdlet.ShouldProcess( (\u0026#34;Overwritting existing file {0}\u0026#34; -f $FilePath), (\u0026#34;Would you like to overwrite {0}?\u0026#34; -f $FilePath), \u0026#34;Create File Prompt\u0026#34; ) ){ $File = New-Item -Path $FilePath -ItemType File -Force -ErrorAction Stop } } else{ ... } } catch{ Throw \u0026#34;$($_.Exception.Message)\u0026#34; } } And so, our final product now looks something like this\nFunction New-PSFile { [CmdletBinding(SupportsShouldProcess=$true,ConfirmImpact=\u0026#39;High\u0026#39;)] Param( # File to Create [Parameter(Mandatory=$true)] [string] $FilePath ) begin{ Write-Verbose \u0026#34;Checking to see if the file provided already exists\u0026#34; $FileExists = Test-Path -Path $FilePath } process{ try { if ($FileExists){ Write-Warning \u0026#34;$FilePath already exists and will be overwritten\u0026#34; if($PSCmdlet.ShouldProcess( (\u0026#34;Overwritting existing file {0}\u0026#34; -f $FilePath), (\u0026#34;Would you like to overwrite {0}?\u0026#34; -f $FilePath), \u0026#34;Create File Prompt\u0026#34; ) ){ $File = New-Item -Path $FilePath -ItemType File -Force -ErrorAction Stop } } else{ Write-Verbose \u0026#34;Creating $FilePath\u0026#34; if($PSCmdlet.ShouldProcess($FilePath,\u0026#34;Create File\u0026#34;)){ $File = New-Item -Path $FilePath -ItemType File -Force -ErrorAction Stop } } } catch{ Throw \u0026#34;$($_.Exception.Message)\u0026#34; } } end{ Write-Verbose \u0026#34;Returning new file details\u0026#34; Return $File } } As always, I hope this comes in handy for someone looking to improve their knowledge, or their powershell scripts and functions!\n","date":"14 January 2019","externalUrl":null,"permalink":"/2019/01/adding-whatif-and-confirm-parameters-to-your-powershell/","section":"Posts","summary":"Want users to preview changes before your PowerShell function makes them? Learn how to add -WhatIf and -Confirm support using SupportsShouldProcess and ShouldProcess() blocks with practical examples.","title":"Adding WhatIf and Confirm Parameters to your Powershell","type":"posts"},{"content":"","date":"14 January 2019","externalUrl":null,"permalink":"/tags/scripting/","section":"Tags","summary":"","title":"Scripting","type":"tags"},{"content":"I\u0026rsquo;d like to start with a shout out to Philip Elder, for he came up with the initial idea and script that I\u0026rsquo;ve used here.\nOne thing that\u0026rsquo;s not always obvious when dealing with S2D Clusters is how much of your Storage Pool has been provisioned and how much capacity, if any, is left.\nTo help with this, we came up with be script you\u0026rsquo;ll see at the bottom of this article.\nIt\u0026rsquo;s designed to be run both locally on a cluster host and against multiple clusters remotely.\nSo what can you expect to get out of this script?\nTotal Size - This is your RAW capacity in the pool Allocated Size - This is the RAW amount of storage already allocated to Virtual Disks RAW Free Space - This is your remaining capacity in the pool Mirror Available - This is how much space you can provision as Mirror Volumes, it assumes 2-way mirror for 2-Nodes and 3-way mirror for 3+ Nodes Parity Available - This is how much space you can provision as Parity Volumes Reserved Space, this is how much space needs to be retained for rebuilds after disk failure So how do you run this?\nWell it\u0026rsquo;s very simple, you can just run the command with nothing else directly on a cluster host and get an output\nGet-PoolStats | ft -au Or you can run it remotely against multiple clusters\nGet-PoolStats -CimSession Cluster-Gen13,Cluster-Gen14 | ft -au Get-StoragePool -FriendlyName S2D* -CimSession Cluster-Gen13,Cluster-Gen14 | Get-PoolStats | ft -au As always, I hope this script helps someone else out there\nfunction Get-PoolStats { [CmdletBinding()] param( # Remote machines to query [alias(\u0026#34;ComputerName\u0026#34;)] [CimSession[]]$CimSession = \u0026#34;localhost\u0026#34;, # Storage Pools you want to query [PSTypeName(\u0026#34;Microsoft.Management.Infrastructure.CimInstance#ROOT/Microsoft/Windows/Storage/MSFT_StoragePool\u0026#34;)] [parameter( Position=0, Mandatory=$false, ValueFromPipeline=$true )] $StoragePool = (Get-StoragePool -CimSession $CimSession | Where-Object IsPrimordial -eq $false) ) begin{ Write-Verbose \u0026#34;[$((get-date).TimeOfDay.ToString()) BEGIN ] Starting: $($MyInvocation.Mycommand)\u0026#34; Write-Verbose \u0026#34;[$((get-date).TimeOfDay.ToString()) BEGIN ] Initialising array\u0026#34; $Results = @() #region: Helper Functions Write-Verbose \u0026#34;[$((get-date).TimeOfDay.ToString()) BEGIN ] Initialising helper functions\u0026#34; Function Format-Bytes { Param ( $RawValue ) $i = 0 ; $Labels = (\u0026#34;B\u0026#34;, \u0026#34;KB\u0026#34;, \u0026#34;MB\u0026#34;, \u0026#34;GB\u0026#34;, \u0026#34;TB\u0026#34;, \u0026#34;PB\u0026#34;, \u0026#34;EB\u0026#34;, \u0026#34;ZB\u0026#34;, \u0026#34;YB\u0026#34;) Do { if ( $RawValue -Gt 1024 ) { $RawValue /= 1024 ; $i++ } } While ( $RawValue -Gt 1024 ) # Return [String][Math]::Round($RawValue) + \u0026#34; \u0026#34; + $Labels[$i] } #endregion } process{ Write-Verbose \u0026#34;[$((get-date).TimeOfDay.ToString()) PROCESS ] Starting process block\u0026#34; Foreach($Pool in $StoragePool){ Write-Verbose \u0026#34;[$((get-date).TimeOfDay.ToString()) PROCESS ] Starting process $($Pool.FriendlyName)\u0026#34; Write-Verbose \u0026#34;[$((get-date).TimeOfDay.ToString()) PROCESS ] Calculating Parity Efficiency\u0026#34; $PhysicalDisks = $Pool | Get-PhysicalDisk -CimSession $Pool.CimSystemProperties.ServerName $StorageNodes = ($Pool | Get-StorageSubSystem | Get-StorageNode).Count $SlowTierMediaType = ( $PhysicalDisks | Where-Object{ $_.Usage -ieq \u0026#34;Auto-Select\u0026#34; } ).MediaType | Sort | Get-Unique if($SlowTierMediaType -ieq \u0026#34;NVMe\u0026#34; -or $SlowTierMediaType -ieq \u0026#34;SSD\u0026#34;){ # All-flash! if ($StorageNodes -lt 7) { $ParityEfficiency = 2 / (2 + 2); } elseif ($StorageNodes -lt 9) { $ParityEfficiency = 4 / (4 + 2); } elseif ($StorageNodes -lt 16) { $ParityEfficiency = 6 / (6 + 2); } else { $ParityEfficiency = 12 / (12 + 2 + 1); # LRC } }else{ # Hybrid if ($StorageNodes -lt 7) { $ParityEfficiency = 2 / (2 + 2); } elseif ($StorageNodes -lt 12) { $ParityEfficiency = 4 / (4 + 2); } else { $ParityEfficiency = 8 / (8 + 2 + 1); # LRC } } Write-Verbose \u0026#34;[$((get-date).TimeOfDay.ToString()) PROCESS ] Parity Efficiency is $ParityEfficiency\u0026#34; Write-Verbose \u0026#34;[$((get-date).TimeOfDay.ToString()) PROCESS ] Calculating Mirror Efficiency\u0026#34; $MirrorEfficiency = 1 / ( ( $Pool | Get-ResiliencySetting -Name Mirror ).PhysicalDiskRedundancyDefault + 1 ) Write-Verbose \u0026#34;[$((get-date).TimeOfDay.ToString()) PROCESS ] Mirror Efficiency is $MirrorEfficiency\u0026#34; Write-Verbose \u0026#34;[$((get-date).TimeOfDay.ToString()) PROCESS ] Calculating Rebuild Space\u0026#34; $LargestDisk = $PhysicalDisks | Where-Object{ $_.Usage -ieq \u0026#34;Auto-Select\u0026#34; } | Sort-Object Size -Descending | Select-Object -First 1 -ExpandProperty Size If($StorageNodes -gt 4){ $RebuildSpace = $LargestDisk * 4 }else{ $RebuildSpace = $LargestDisk * $StorageNodes } Write-Verbose \u0026#34;[$((get-date).TimeOfDay.ToString()) PROCESS ] Calculating Pool Stats\u0026#34; $FriendlyName = $Pool.FriendlyName $Size = Format-Bytes -RawValue $Pool.Size $AllocatedSize = Format-Bytes -RawValue $Pool.AllocatedSize $RawFreeSpace = Format-Bytes -RawValue ($Pool.Size - $Pool.AllocatedSize) $RebuildSpaceNeeded = Format-Bytes -RawValue $RebuildSpace $MirrorAvailable = Format-Bytes -RawValue ( ( $Pool.Size - $Pool.AllocatedSize - $RebuildSpace ) * $MirrorEfficiency) $ParityAvailable = Format-Bytes -RawValue ( ( $Pool.Size - $Pool.AllocatedSize - $RebuildSpace ) * $ParityEfficiency) Write-Verbose \u0026#34;[$((get-date).TimeOfDay.ToString()) PROCESS ] Adding output to results array\u0026#34; $Results += [pscustomobject][ordered]@{ Name = $FriendlyName TotalSize = $Size AllocatedSize = $AllocatedSize RawFreeSpace = $RawFreeSpace MirrorAvailable = $MirrorAvailable ParityAvailable = $ParityAvailable ReservedSpace = $RebuildSpaceNeeded } Write-Verbose \u0026#34;[$((get-date).TimeOfDay.ToString()) PROCESS ] Finished processing $($Pool.FriendlyName)\u0026#34; } } end{ Write-Verbose \u0026#34;[$((get-date).TimeOfDay.ToString()) END ] Returning results\u0026#34; Write-Output $Results } } ","date":"23 December 2018","externalUrl":null,"permalink":"/2018/12/get-a-pretty-view-of-your-s2d-storage-pools/","section":"Posts","summary":"Ever wondered how much of your S2D Storage Pool is actually available? This PowerShell function shows total size, allocated space, Mirror/Parity available capacity, and reserved space—locally or across multiple clusters.","title":"Get a pretty view of your S2D Storage Pools","type":"posts"},{"content":"If you\u0026rsquo;ve ever dealt with a SAN or Storage guy before, you\u0026rsquo;ll know that they usually have a huge passion for cache stats. This is because the secret sauce of accelerating cheap storage for years has been to stick a small amount of expensive but super fast flash in front of your slower spinning disk, or in recent years, your cheaper low endurance SSDs.\nBecause of this, it was always a good idea to keep an eye on how your cache was going, making sure things like Cache Hit Misses were low, and that your Write Cache wasn\u0026rsquo;t overallocated.\nAnd Storage Spaces Direct (S2D) is no different today, especially in Hybrid (SSD+HDD) deployments.\nToday, we\u0026rsquo;ll focus in on the Write Cache portion of S2D\u0026rsquo;s caching technology, as it\u0026rsquo;s easy to forget about and overlook.\nNow if you\u0026rsquo;re running Windows Server 2019, the new Cluster Performance History makes this very easy for you.\nIf you want to see the total Cluster cache write usage:\nGet-ClusterPerf -ClusterSeriesName PhysicalDisk.Cache.Size.Dirty,PhysicalDisk.Cache.Size.Total Or if you want to see the per node usage:\nGet-ClusterNode | Get-ClusterPerf -ClusterNodeSeriesName PhysicalDisk.Cache.Size.Dirty,PhysicalDisk.Cache.Size.Total This is all well and good if you\u0026rsquo;ve already made the mode to Windows Server 2019, but what if you\u0026rsquo;re still on Windows Server 2016?\nWell the good news is that the counters still exist, however they\u0026rsquo;re not as easy to read as they are in Windows Server 2019.\nTo get the same information, we need to look at the following Performance Counters:\nCluster Storage Cache Stores Cache Pages Bytes Cache Pages Dirty Cache Pages Bytes is pretty self explanatory, it\u0026rsquo;s the size of the cache. Cache Pages Dirty however looks like some alien number that doesn\u0026rsquo;t match up to anything, and that\u0026rsquo;s partly true, but only because we\u0026rsquo;re still missing a key piece of information, how big is a cache page?\nFinding that is as simple as running (Get-ClusterS2D).CachePageSizeKBytes With this, we can take our dirty counter value and times it by the cache page size to work out the write cache allocation.\nNow that\u0026rsquo;s now the easiest thing to check when you\u0026rsquo;re in a hurry, or across multiple hosts and clusters, so I\u0026rsquo;ve created a small function to wrap it all up for you.\nFunction Get-ClusterWriteCacheUsage { [cmdletbinding()] param( # Cluster\u0026#39;s to query [string[]]$ClusterName=\u0026#34;localhost\u0026#34;, # Show only the total per node [switch]$TotalOnly ) begin { # Establish helper functions Function Format-Bytes { Param ( $RawValue ) $i = 0 ; $Labels = (\u0026#34;B\u0026#34;, \u0026#34;KB\u0026#34;, \u0026#34;MB\u0026#34;, \u0026#34;GB\u0026#34;, \u0026#34;TB\u0026#34;, \u0026#34;PB\u0026#34;, \u0026#34;EB\u0026#34;, \u0026#34;ZB\u0026#34;, \u0026#34;YB\u0026#34;) Do { if ( $RawValue -Gt 1024 ) { $RawValue /= 1024 ; $i++ } } While ( $RawValue -Gt 1024 ) # Return [String][Math]::Round($RawValue,2) + \u0026#34; \u0026#34; + $Labels[$i] } } Process { # Start processing supplied cluster names Foreach ($Name in $ClusterName) { # Confirm the cluster exists try{ $Cluster = (Get-Cluster -Name $Name -ErrorAction Stop).Name }catch{ throw \u0026#34;Cluster Name $Name supplied, can\u0026#39;t be found\u0026#34; } # Query for Nodes $Nodes = (Get-ClusterNode -Cluster $Cluster) # Query for Cluster Cache Page Size [int64]$PageSize = (Get-ClusterS2D -CimSession $Cluster).CachePageSizeKBytes * 1KB # Loop through each node to get performance counters Foreach ($Node in $Nodes) { $NodeName = $Node.Name # Determine if we need all instances or just _total if ($TotalOnly -eq $true) { $Query = \u0026#34;_Total\u0026#34; } else { $Query = \u0026#34;*\u0026#34; } $DirtyCounter = \u0026#34;\\\\$NodeName\\Cluster Storage Cache Stores($Query)\\Cache Pages Dirty\u0026#34; $SizeCounter = \u0026#34;\\\\$NodeName\\Cluster Storage Cache Stores($Query)\\Cache Pages\u0026#34; # Collect the actual counter data $Data = (Get-Counter -Counter $DirtyCounter -ComputerName $NodeName).CounterSamples $Data += (Get-Counter -Counter $SizeCounter -ComputerName $NodeName).CounterSamples # Determine the names of the disks queried $Instances = ($Data | Sort-Object InstanceName).InstanceName | Get-Unique # Find matching data for each disk and return it formated Foreach ($Instance in $Instances) { # get Matching Data $CacheSize = ( $Data |Where-Object { ($_.InstanceName -eq $Instance) -and ($_.Path -ilike \u0026#34;*\\cache pages\u0026#34;) } ).RawValue * $PageSize $CacheUsage = ( $Data |Where-Object { ($_.InstanceName -eq $Instance) -and ($_.Path -ilike \u0026#34;*\\cache pages dirty\u0026#34;) } ).RawValue * $PageSize # Format data into a PS Object and return it [pscustomobject][ordered]@{ ComputerName = $NodeName Instance = $Instance WriteCacheUsage = Format-Bytes -RawValue $CacheUsage CacheSize = Format-Bytes -RawValue $CacheSize } } } } } } Hopefully this can help give some of you out until you can upgrade to Windows Server 2019!\n","date":"22 December 2018","externalUrl":null,"permalink":"/2018/12/looking-at-the-write-cache-in-storage-spaces-direct/","section":"Posts","summary":"Cache stats matter! Learn how to monitor your S2D write cache allocation using Windows Server 2019’s Cluster Performance History or Windows Server 2016’s performance counters, plus a handy PowerShell function.","title":"Looking at the Write Cache in Storage Spaces Direct","type":"posts"},{"content":"","date":"22 December 2018","externalUrl":null,"permalink":"/tags/ws2016/","section":"Tags","summary":"","title":"WS2016","type":"tags"},{"content":"","date":"6 September 2018","externalUrl":null,"permalink":"/tags/5120/","section":"Tags","summary":"","title":"5120","type":"tags"},{"content":"","date":"6 September 2018","externalUrl":null,"permalink":"/tags/bug/","section":"Tags","summary":"","title":"Bug","type":"tags"},{"content":"","date":"6 September 2018","externalUrl":null,"permalink":"/tags/event-id-5120/","section":"Tags","summary":"","title":"Event ID 5120","type":"tags"},{"content":"If you\u0026rsquo;re running a Storage Spaces Direct (S2D) Cluster, you might have noticed some instability in recent months, specifically when it comes to patching and performing maintenance. Well you\u0026rsquo;re in luck because 5 days ago, Microsoft released a new KB article that helps explain why you might have seen issues.\nThe scenario targeted by the Microsoft article is S2D Clusters running May (KB4103723) or later patch levels, where you experience Event ID 5120 during patching or maintenance, leading to things like CSV timeouts, VM pauses, or even VM crashes. On top of this, the CSV crash might trigger a live dump, which can cause the node to drop out of the cluster when under load.\nCrazy right? Microsoft\u0026rsquo;s explanation for this is:\n\u0026ldquo;In the May 8, 2018, cumulative update, a change was introduced to add SMB Resilient Handles for the Storage Spaces Direct intra-cluster SMB network sessions. This was done to improve resiliency to transient network failures and improve how RoCE handles network congestion. Adding these improvements has also inadvertently increased time-outs when SMB connections try to reconnect and waits to time-out when a node is restarted. These issues can affect a system that is under stress. During unplanned downtime, IO pauses of up to 60 seconds have also been observed while the system waits for connections to time-out.\u0026rdquo;\nSo how can you avoid this? Well good news is Microsoft has a workaround for planned maintenance, and that\u0026rsquo;s rolling back to the old Storage Maintenance Mode that was removed in September CU last year!\nGet-StorageFaultDomain -type StorageScaleUnit | Where-Object {$_.FriendlyName -eq \u0026#34;\u0026lt;NodeName\u0026gt;\u0026#34;} | Enable-StorageMaintenanceMode If you\u0026rsquo;re managing a larger deployment of S2D, you\u0026rsquo;re hopefully taking advantage of Cluster Aware Updating (CAU), so that you don\u0026rsquo;t sit up all night watching your cluster patch. Unfortunately, CAU no longer triggers this storage maintenance mode (see here), so we need to make use of Pre and Post Scripts. CAU Pre and Post scripts are great tools, they can execute scripts on each node before entering maintenance mode, and after leaving maintenance mode, and as such, they are perfect for executing the workaround for us!\nHere\u0026rsquo;s an example of a Pre-Patching Script that we might use:\n# Check for any outstanding Storage Jobs \u0026#34;Waiting for storage jobs to complete\u0026#34; do { Start-Sleep 5 }until( # Running Repair Jobs are less than 1 ((Get-StorageJob |Where-Object {$_.Name -eq \u0026#39;Repair\u0026#39; -and $_.JobState -ne \u0026#39;Completed\u0026#39;})|Measure-Object).Count -lt 1 ) \u0026#34;Storage Jobs finished\u0026#34; # Suspend Cluster Host to prevent chicken-egg scenario Suspend-ClusterNode -Name $env:COMPUTERNAME -Drain -ForceDrain -Wait # Enter Storage Maintenance Mode try { Get-StorageFaultDomain -type StorageScaleUnit | Where-Object {$_.FriendlyName -eq \u0026#34;$($Env:ComputerName)\u0026#34;} | Enable-StorageMaintenanceMode } catch { Resume-ClusterNode -Name $Env:COMPUTERNAME -Failback throw \u0026#34;Failed to enter storage maintenance mode\u0026#34; } This script will skip ahead of CAU by actually putting the host into cluster maintenance mode itself, this is because entering Storage Maintenance mode kicks off storage rebuilds, which will prevent CAU from being able to do it. Now to avoid this issue ourselves, the script first loops through waiting for any outstanding storage jobs to finish, before attempting to enter Cluster Maintenance Mode.\nAnd here is an example of what we might use in a Post-Patch Script:\n# Check for any nodes left in a Paused State and Resume them If ((get-clusternode -Name $Env:COMPUTERNAME).State -eq \u0026#39;Paused\u0026#39;) { Resume-ClusterNode -Name $Env:COMPUTERNAME -Failback } # Exit Storage Maintenance Mode Get-StorageFaultDomain -type StorageScaleUnit | Where-Object {$_.FriendlyName -eq \u0026#34;$($Env:ComputerName)\u0026#34;} | Disable-StorageMaintenanceMode Now this script is a lot simpler, this just makes sure the node isn\u0026rsquo;t in Cluster Maintenance mode, removes it if it is, and then brings the node out of Storage Maintenance mode.\nHopefully this helps a few of the S2D Admins out there with their cluster, seeing as the MS article isn\u0026rsquo;t very well advertised. Personally I\u0026rsquo;d like to see them add it as a known issue to the Windows CU Patch notes so that everyone finds it before the hit the issue, but we\u0026rsquo;ll see if that happens.\nCurrently there is no ETA on a permanent fix for this, however I\u0026rsquo;ll update the article if more information on this surfaces.\nOriginal MS Article: https://support.microsoft.com/en-nz/help/4462487/\n","date":"6 September 2018","externalUrl":null,"permalink":"/2018/09/you-need-to-change-the-way-you-patch-s2d-clusters/","section":"Posts","summary":"If you’re experiencing Event ID 5120, CSV timeouts, or VM pauses when patching S2D clusters, Microsoft has identified the cause. Here’s the workaround using Storage Maintenance Mode and ready-to-use CAU pre/post scripts.","title":"You need to change the way you patch S2D Clusters","type":"posts"},{"content":"","date":"2 April 2018","externalUrl":null,"permalink":"/tags/ltsb/","section":"Tags","summary":"","title":"LTSB","type":"tags"},{"content":"If you\u0026rsquo;ve been anywhere near Twitter or any Tech Blogs and News sites recently, you would have noticed that Microsoft have dropped their first cut of the next Long-Term Service Branch OS, Windows Server 2019, into the Windows Insider ring for people like you and me to start testing.\nNow most people (like me) don\u0026rsquo;t have a huge amount of spare hardware sitting round for times like this, especially for testing things like Storage Spaces Direct (S2D). However, a Microsoft PFE, Jaromir Kaspar, has built some incredibly crafty Powershell scripts that mean with 3 scripts and about a half hour of your time, you can deploy an entire nested S2D Lab on any Hyper-V Host (Even a Windows 10 Laptop!).\nWhat I\u0026rsquo;m talking about is WS2016Lab, and it\u0026rsquo;s available for anyone to use on GitHub (Link here)\nI\u0026rsquo;m not going to do a walk-through on how to make use of WS2016Lab because if you read the GitHub page and check out the super helpful videos like the one above, you\u0026rsquo;ll be armed with everything you need to get going.\nNow while I was focusing on S2D testing on Windows Server 2019 LTSB Insider Preview, here are just some of the scenarios supported with WS2016Lab:\nNested S2D Hyper-Converged Cluster Physical S2D Hyper-Converged Cluster S2D Converged Cluster (SOFS + Hyper-V) S2D With Bitlocker Storage Replica S2D Bare Metal Deployment from SCVMM Managing S2D with SCVMM Device Guard LAPS SCVMM with SDNExpress Testing Project Honolulu And Many More On top of all these great lab scenarios (most of which you can deploy on your laptop!), there are a number of great S2D Tools, Documentation on CSV Redirection, and just generally great articles around supporting all the technology used in each scenario.\nIf you work with Hyper-V or S2D, or are looking to learn more about it, you can take advantage of these scripts to quickly deploy, and redeploy many scenarios in very little time.\nI highly recommend you check it out\n","date":"2 April 2018","externalUrl":null,"permalink":"/2018/04/using-ws2016lab-to-test-windows-server-2019/","section":"Posts","summary":"WS2016Lab by Jaromir Kaspar lets you deploy an entire nested S2D lab on any Hyper-V host—even a Windows 10 laptop! Perfect for testing Windows Server 2019, S2D, Storage Replica, Project Honolulu, and many more scenarios.","title":"Using WS2016Lab to test Windows Server 2019","type":"posts"},{"content":"","date":"2 April 2018","externalUrl":null,"permalink":"/tags/windows-insider/","section":"Tags","summary":"","title":"Windows Insider","type":"tags"},{"content":"","date":"2 April 2018","externalUrl":null,"permalink":"/tags/ws2016lab/","section":"Tags","summary":"","title":"Ws2016lab","type":"tags"},{"content":"Hi all,\nQuite often the best information on new technology is actually found in blog posts and not actual documentation, and while the documentation for Storage Spaces Direct from Microsoft is great, some of the real gems are in the pre-GA blogs they put up.\nSo below, I hope to keep up a list of essential blog posts from both Microsoft and independent bloggers for those of you who wish to really understand what\u0026rsquo;s happening under the hood!\nOfficial Documentation Deep Dive: The Storage Pool in Storage Spaces Direct (Cosmos Darwin) Don’t do it: consumer-grade solid-state drives (SSD) in Storage Spaces Direct (Dan Lovinger) Volume resiliency and efficiency in Storage Spaces Direct (Claus Joergensen) Understanding SSD endurance: drive writes per day (DWPD), terabytes written (TBW), and the minimum recommended for Storage Spaces Direct (Cosmos Darwin) If you think I\u0026rsquo;ve missed any posts off my list, feel free to leave me comment or flick me a message on twitter\n","date":"15 October 2017","externalUrl":null,"permalink":"/2017/10/must-read-storage-spaces-direct-blog-posts/","section":"Posts","summary":"The best information on S2D often comes from blog posts rather than documentation. Here’s my curated list of essential reads covering storage pools, SSD endurance, volume resiliency, and why you shouldn’t use consumer SSDs.","title":"Must Read Storage Spaces Direct Blog Posts","type":"posts"},{"content":"UPDATE(2017-09-19): Microsoft have officially recognized the bug and have a KB describing the symptoms and workaround much like the below. See here: https://support.microsoft.com/en-us/help/4043361/disks-in-maintenance-mode-status-after-september-cumulative-update-kb\nI was patching our dev cluster the other day and came across a new issue when applying the latest September Cumulative Update (KB4038782), and it seems others on the internet have hit this issue as well.\nBackground # First, a bit of background on the expected behaviour when performing maintenance:\nBasically when you are performing maintenance on a Storage Spaces Direct (S2D) Cluster, you would normally use Failover Cluster Manager (GUI or Powershell) to Pause and Drain the node first, and then patch and reboot it, and eventually resume and fail back its rolls.\nNow doing this would in turn, mark the physical disks associated with that host as being in maintenance mode during this period to redirect IO away from them, and then when the host is resumed, the disks are taken out of maintenance mode and IO is resumed to them and the storage re-sync begins.\nThis is all automated for you if you use the awesome Cluster Aware Updating (CAU) features, which will patch whole clusters for you without your manual involvement.\nProblem # What I found while patching this month, both manually and with CAU, is that when the hosts go into maintenance mode and are paused and drained, their disks are also marked as being in maintenance mode, however after patching and rebooting, they get resumed but their disks stay in maintenance mode.\nWhat this means, is that if you\u0026rsquo;re using CAU, it will fail to patch the cluster after the first host or two, depending on your resiliency, as it doesn\u0026rsquo;t have enough spare capacity left to take more disks out of maintenance mode, even though all the hosts are up and healthy.\nYou can check this by running the following Powershell on a cluster host\nGet-StorageNode | %{ $_.Name; $_ | Get-PhysicalDisk -PhysicallyConnected } Workaround and Fix # Now, if you\u0026rsquo;ve already started patching and need to recover from this, you can use the following Powershell to remediate the hosts you\u0026rsquo;ve patched\nRepair-ClusterStorageSpacesDirect -Node [hostname] -DisableStorageMaintenanceMode If you haven\u0026rsquo;t patched, then you can avoid this by choosing to \u0026lsquo;Pause and Don\u0026rsquo;t Drain\u0026rsquo; your hosts in Failover Cluster Manager, and then manually live migrate your VMs and Virtual Disks to other cluster members before patching and rebooting the host, as this will avoid the physical disks being put into maintenance mode in the first place.\nMy take on the problem # Having dealt with S2D for a while, I think what we\u0026rsquo;re seeing here is a change in behaviour to how maintenance is performed on S2D Cluster hosts, and so when this new logic has been pushed out with the September CU, it\u0026rsquo;s conflicting with the old logic and leaving things in a halfway house.\nI very much doubt we will see this problem in next month\u0026rsquo;s patching, as it looks like once September CU is applied, the issue isn\u0026rsquo;t reproducible when putting hosts in and out of maintenance mode.\nHopefully this helps anyone else coming across this issue\n","date":"16 September 2017","externalUrl":null,"permalink":"/2017/09/bug-when-applying-kb4038782-september-cu-to-storage-spaces-direct-clusters/","section":"Posts","summary":"Discovered a bug where physical disks stay in maintenance mode after applying September CU to S2D clusters. This breaks CAU patching and causes capacity issues. Here’s how to recover and avoid the problem.","title":"Bug when applying KB4038782 September CU to Storage Spaces Direct Clusters","type":"posts"},{"content":"","date":"16 September 2017","externalUrl":null,"permalink":"/tags/kb4038782/","section":"Tags","summary":"","title":"KB4038782","type":"tags"},{"content":"","date":"16 September 2017","externalUrl":null,"permalink":"/tags/september-cu/","section":"Tags","summary":"","title":"September CU","type":"tags"},{"content":"I\u0026rsquo;ve been deploying a few Storage Spaces Direct (S2D) clusters lately, and I noticed a slight mis-configuration that can occur on deployment.\nNormally when deploying S2D, the disk types in the nodes are detected and the fastest disk (usually NVMe or SSD) is assigned to the cache, while the next fastest is used for the Performance Tier and the slowest being used in the Capacity Tier. So if you have NVMe, SSD and HDD, you would end up with an NVMe Cache, a SSD Performance Tier and a HDD Capacity Tier. With only 2 disk types, either NVMe+SSD, NVMe+HDD or SSD+HDD, the fastest disk is used for Cache and the other used for both the Performance and Capacity Tiers.\nIt seems there is a bug that is causing the Performance Tier to set its mediatype to the fastest disk in the system, even if that disk is already allocated to cache.\nIn my deployments, I\u0026rsquo;ve got 4x SSD and 12x HDD in each my hosts, with the expectation that the SSD is used for cache and the HDD is mirrored for the Performance Tier and in Parity for Capacity Tier. However even though the SSD is being assigned correctly to the Cache, the Performace Tier shows as an SSD mediatype, preventing me from deploying volumes with mirrored HDD until this is correctly.\nYou can check your own systems by running the below Powershell Command\nGet-StorageTier | select FriendlyName, ResiliencySettingName, MediaType, PhysicalDiskRedundancy If you\u0026rsquo;ve got the same problem, it can be very easily corrected by simply changing the mediatype on the Tier back to HDD\nGet-StorageTier -FriendlyName Performance | Set-StorageTier -MediaType HDD I\u0026rsquo;m sure there will be a permanent fix along for this soon, but in the mean time I hope this helps others who come across the same problem.\n","date":"8 November 2016","externalUrl":null,"permalink":"/2016/11/s2d-storage-tiers-misconfiguration-bug/","section":"Posts","summary":"Discovered a bug where S2D incorrectly sets the Performance Tier mediatype to SSD even when SSDs are assigned to cache. Learn how to check your configuration and fix it with a simple PowerShell command.","title":"S2D Storage Tiers misconfiguration bug","type":"posts"},{"content":"I\u0026rsquo;ve used System Center Virtual Machine Manager for a few years now, and I\u0026rsquo;ve come to like its ups and deal with its downs.\nIt has a lot of great features, like bare-metal deployments and logical networks, which when executed correctly are both huge time savers and take away a lot of human error.\nWith SCVMM, let\u0026rsquo;s start with some of a new additions in 2016:\nConverting \u0026lsquo;Standard Switches\u0026rsquo; on hosts to Logical Switches Too often in the past I\u0026rsquo;ve retro-fitted VMM into a Hyper-V Environment and had to wrestle with removing existing Standard Switches and replacing them with Logical switches and had to deal with migrating VMs, losing connectivity, rolling back. Now all that pain is gone with a single button that allows you to convert your Standard Switch to a Logical Switch if one with matching properties exists. Full Orchestration for Rolling Cluster Upgrades One of the coolest features of 2016 is Rolling Cluster upgrades, it makes upgrades forever easier by allowing you to run mixed mode clusters during an upgrade process and then raise then cluster functional level once all hosts are upgraded. Think of it like you would Active Directory and Domain Controllers, upgrade them all to the new level one at a time and then raise your functional level. VMM builds on top of this by combining it with bare-metal deployments to automate the entire process! How freaking cool is that? Especially with the next point Support for \u0026lsquo;Storage Spaces Direct\u0026rsquo; and Storage QoS You can deploy a complete hyperconverged cluster using VMMs bare-metal deployment Create new volumes on your S2D clusters Manage your Storage QoS policies with a nice GUI And many more storage tasks Now some of the things that I feel are still missing in VMM:\n\u0026lsquo;Getting started\u0026rsquo; GUI after initial installation Anyone who\u0026rsquo;s deployed a VMware vCenter will know what I\u0026rsquo;m talking about, it\u0026rsquo;s that lovely \u0026lsquo;Getting Started\u0026rsquo; tab on everything in the GUI that helps you work your way through creating your Datacenters (aka. Host Groups), Adding your hosts, creating your clusters, deploying your first VM. It makes dealing with vCenter for the first time just that little bit easier, and it doesn\u0026rsquo;t feel like you need a PHD to configure it or if you do something wrong the thing will implode. For those that have never touch VMware, here\u0026rsquo;s what I\u0026rsquo;m talking about Advanced use of Storage QoS Features Now creation of Storage QoS policies in VMM has a nice easy to use GUI in front of it, but they could\u0026rsquo;ve done so much more with it Delegation of policies to Clouds/Tenants so that VM admins can assign the right policies to their VMs without needing to be fabric admins Ability to set policies against VMs/Clouds/Host Groups. It\u0026rsquo;d be nice to get a default QoS policy against a cloud and have it automatically propagate to all child VM disks. And then be able to get more granular setting policies against a VM or specific disks on a VM that need special treatment. Instead my only option is to set a policy manually (or scripted) against even VM disk, just like if I didn\u0026rsquo;t have VMM. Quotas not counting compute resources of powered off VMs Now quotas and Cloud Capacity limitations are a great way to give a department or client access to a subset of your resources and not have to worry about them consuming everything while you\u0026rsquo;re not looking, but what if that department if full of Devs who have multiple environments but only have 1 running at a time? Well they don\u0026rsquo;t need resources for all of their environments, but just enough to power on 1 of them. Too bad for you VMM counts the CPU and Memory usage of powered off VMs towards their Quota too. Configuration of VLANs on host physical adapters Bare-metal deployment is great, it allows you to push out an identical configuration to all of your hosts. But what if you have NICs you don\u0026rsquo;t want to put on a switch, say for storage traffic? And they need to have a VLAN configured on them? Well VMM currently doesn\u0026rsquo;t let you do that. Instead after VMM has deployed the host you need to go through with your Set-NetAdapter command and configure those VLANs. Automatic configuration of VMQ settings for Bare-metal deployed hosts VMQ is something all Hyper-V admins will struggle with at some stage or another. It would be nice if VMM could take away the pain when deploying hosts by looking at the host hardware, the networking it\u0026rsquo;s going to apply and then work out the best VMQ settings to apply. Tenant view of cloud capacity Now this may seem obvious, but it\u0026rsquo;s not there. You as an Administrator can see the lovely cloud capacity view, however the tenant admin cannot. No native support of Hyper-V Replica This one for me is just mind-boggling. VMM by name is designed to sit overtop of Hyper-V to help you manage your VMs. How is it meant to do that though when it doesn\u0026rsquo;t support all the core Hyper-V features? Like say Hyper-V Replica? FYI don\u0026rsquo;t bother telling me if I integrate VMM with Azure Site Recovery then I\u0026rsquo;ll get Hyper-V Replica in VMM, because why should I pay for a cloud service to manage my on-prem service to manage my on-prem to on-prem service? That\u0026rsquo;s also just a lot of moving parts I don\u0026rsquo;t want to have to worry about. One Powershell to rule them all Again taking a leaf out of VMware\u0026rsquo;s book, it would be create if there was just 1 powershell module and 1 set of commands for managing Hyper-V hosts and VMs whether they be standalone hosts, in a cluster or managed by VMM. It would be nice if the VMM powershell commands returned at least the same details that their Hyper-V modules counterparts do - eg. where is my VM uptime in Get-SCVirtualMachine? And why must you alias Get-VM and break my scripts? UPDATE: Tenants unable to update VM Configuration Versions If the whole point of having Tenant Admins is to give power back to the users for all things related to their VMs, then why can\u0026rsquo;t they upgrade the VM Configuration version? Why must this be done by a fabric admin? This may have ended up sounding a bit ranty, but I do like VMM, it does make my life easier on the whole when managing Hyper-V environments. If they could just get the last few pieces right, then I think we\u0026rsquo;d see more people coming across from VMware land.\n","date":"24 October 2016","externalUrl":null,"permalink":"/2016/10/my-wishlist-for-system-center-virtual-machine-manager/","section":"Posts","summary":"SCVMM 2016 brought great features like Standard-to-Logical Switch conversion and S2D support. But there’s still room for improvement—here’s my wishlist including a Getting Started GUI, advanced Storage QoS, and native Hyper-V Replica support.","title":"My Wishlist for System Center Virtual Machine Manager","type":"posts"},{"content":"","date":"24 October 2016","externalUrl":null,"permalink":"/tags/system-center/","section":"Tags","summary":"","title":"System Center","type":"tags"},{"content":"","date":"24 October 2016","externalUrl":null,"permalink":"/tags/virtual-machine-manager/","section":"Tags","summary":"","title":"Virtual Machine Manager","type":"tags"},{"content":"","date":"24 October 2016","externalUrl":null,"permalink":"/tags/wishlist/","section":"Tags","summary":"","title":"Wishlist","type":"tags"},{"content":"You should try to find some internet connection to browse here.\n","date":"16 October 2016","externalUrl":null,"permalink":"/offline/","section":"Home","summary":"You should try to find some internet connection to browse here.\n","title":"Oops, you are offline.","type":"offline"},{"content":"","date":"6 October 2016","externalUrl":null,"permalink":"/categories/hyper-v/","section":"Categories","summary":"","title":"Hyper-V","type":"categories"},{"content":"","date":"6 October 2016","externalUrl":null,"permalink":"/tags/hyper-v/","section":"Tags","summary":"","title":"Hyper-V","type":"tags"},{"content":"We\u0026rsquo;ve all had the case where there was a volume running hot on your cluster and you spend ages wrestling with perf counters to try to find that VM that\u0026rsquo;s causing your storage to burn. Well let me introduce you to a magical new command in Windows Server 2016\nGet-StorageQoSFlow This miracle command can give you insights on all the VHD(x)s running on your cluster, revealing IOPS, Latency and Bandwidth stats for them all without the need for large-scale monitoring solutions.\nLet\u0026rsquo;s look at a few examples of how we can use this to our advantage, starting with the top 5 busiest VHD(x)s\nGet-StorageQoSFlow -CimSession ClusterName | Sort-Object InitiatorIOPS -Descending | select -First 5 In my example above, we can see straight away both the busiest machine, and exactly which of its disks is creating the load.\nNext let\u0026rsquo;s move on to checking the performance of a specific VM, which would look like this\nGet-StorageQoSFlow -InitiatorName VMName -CimSession ClusterName Now these two uses of the command alone have already helped a fellow admin find several VMs that were thought to be idle, actually consuming around about 15,000 IOPS due to a few rough processes. These were precious IOPS that were better served being available to more critical services.\nFor bonus points, here are a few more commands to look at when looking for storage stats\n# Get stats for any CSV Get-StorageQoSVolume -CimSession ClusterName # Get stats for a Storage Spaces Direct Cluster Get-StorageSubSystem clu* | Get-StorageHealthReport # Get stats from the health service for all CSVs Get-Volume -CimSession ClusterName | ?{$_.FileSystem -eq \u0026#39;CSVFS\u0026#39;} | Get-StorageHealthReport -CimSession ClusterName Until next time!\n","date":"6 October 2016","externalUrl":null,"permalink":"/2016/10/identifying-storage-intensive-vms-in-hyper-v-2016-clusters/","section":"Posts","summary":"Discover the magical Get-StorageQoSFlow command in Windows Server 2016 that reveals IOPS, latency, and bandwidth stats for all VHD(x)s on your cluster—perfect for finding those VMs burning through your storage.","title":"Identifying storage intensive VMs in Hyper-V 2016 Clusters","type":"posts"},{"content":"As many of you would have seen, Windows Server 2016 has been officially launched, with evaluation media available and General Availability slated for later this month.\nOne of the great new features in this release, is Storage Spaces Direct, a Software-Defined Storage Solution. There is already plenty of information available on how to get this up and running on Microsoft Docs, but I thought I\u0026rsquo;d share some of the operational tasks that aren\u0026rsquo;t so obvious, starting with expanding volumes.\nFirstly we want to get the current size of the existing storage tiers that make up our volume\nGet-VirtualDisk -FriendlyName vol1 | Get-StorageTier | Format-Table FriendlyName, @{Label=’Freespace(GB)’;Expression={$_.Size/1GB}} -autosize Now in this example, we\u0026rsquo;re using a Multi-Resiliency Virtual Disk, which allows us to combine the performance of Mirror with the efficiency of Parity to get the best of both worlds. Let\u0026rsquo;s say this volume has a SQL Server on it, and I know my working data set hasn\u0026rsquo;t increased but I\u0026rsquo;ve got lots of cold data and my volume is almost full. I want to just add capacity to the volume to continue to store more cold data.\nWe want to select just the Parity tier and expand that one\nGet-VirtualDisk -FriendlyName vol1 | Get-StorageTier | ?{$_.ResiliencySettingName -eq \u0026#39;Parity\u0026#39;} | Resize-StorageTier -Size 1000GB And then expand the partition to match the new size\nGet-VirtualDisk -FriendlyName vol1 | Get-Disk | Get-Partition | ?{$_.type -eq \u0026#39;Basic\u0026#39;} | Resize-Partition -Size 1100GB Now if we check the storage tiers again we should see our new sizes\nGet-VirtualDisk -FriendlyName vol1 | Get-StorageTier | Format-Table FriendlyName, @{Label=’Freespace(GB)’;Expression={$_.Size/1GB}} -autosize If you wanted to add more Performance Tier to your volume to account for an increase in your active working set, or the data that is write intensive, then you would just have to swap out Parity for Mirror in the command where we expanded the tier.\nShrinking of S2D (Storage Spaces Direct) volumes is not currently supported, however this is a less common scenario.\nI\u0026rsquo;ll be posting more tips like this around Storage in Windows Server 2016 over the next few weeks\n","date":"3 October 2016","externalUrl":null,"permalink":"/2016/10/expanding-storage-spaces-direct-volumes/","section":"Posts","summary":"A step-by-step guide to expanding S2D volumes using PowerShell. Learn how to resize individual storage tiers (Mirror or Parity) and expand partitions to match your workload needs.","title":"Expanding Storage Spaces Direct Volumes","type":"posts"},{"content":"","date":"2 October 2016","externalUrl":null,"permalink":"/tags/ignite/","section":"Tags","summary":"","title":"Ignite","type":"tags"},{"content":"","date":"2 October 2016","externalUrl":null,"permalink":"/tags/msignite/","section":"Tags","summary":"","title":"MSIgnite","type":"tags"},{"content":"","date":"2 October 2016","externalUrl":null,"permalink":"/tags/speaking/","section":"Tags","summary":"","title":"Speaking","type":"tags"},{"content":"While sitting in LAX Airport with some time to kill I thought I\u0026rsquo;d reflect on the last week.\nI\u0026rsquo;ve spent the last week at the Microsoft Ignite conference in Atlanta, and what a crazy but fantastic week it has been. Starting with only finding out 2 weeks before the start of the conference that I was invited to speak, frantically trying to sort accommodation and flights, and finally ending with speaking at the conference itself.\nIt was my first time speaking publicly, and I was super nervous about it, but luckily I had a band of seasoned speakers at the ready to walk me through it.\nMy piece was short though and more painless than expected, I feel I\u0026rsquo;ve now got a new achievement under my belt and I should make an effort to do more of these to build up confidence.\nThe rest of the event was a blast, I got to go see a bunch of awesome people talk, but even better was the chance to sit down and talk with them outside of the conference. I got some real insights from talking with Microsoft Employees, Vendors and other IT professionals that I wouldn\u0026rsquo;t have otherwise had access to in little old New Zealand.\nI highly recommend anyone who is given the opportunity to speak publically, take it. It\u0026rsquo;ll be scary but it\u0026rsquo;s so worth it.\nSee the talk here: https://youtu.be/-LK2ViRGbWs?t=41m59s\n","date":"2 October 2016","externalUrl":null,"permalink":"/2016/10/speaking-at-microsoft-ignite/","section":"Posts","summary":"My first time speaking publicly at Microsoft Ignite was nerve-wracking but rewarding. From last-minute travel arrangements to connecting with industry experts, here’s my experience and why you should take any opportunity to speak.","title":"Speaking at Microsoft Ignite","type":"posts"},{"content":"I\u0026rsquo;ve decided it\u0026rsquo;s time to get more active online, I\u0026rsquo;ve always been lurking in forums and posting on Reddit, but I want to give back more.\nFor me, blogs are one of the biggest sources of information when looking at new technology. Whether it\u0026rsquo;s an honest review of a product or a deployment guide that highlights all the \u0026lsquo;gotchas\u0026rsquo; that would otherwise catch out first timers.\nSo I\u0026rsquo;m going to give it my best shot to write at least one useful post a week, sharing gotchas and other learnings that might help someone else out.\nNext week will probably be an exception though as I\u0026rsquo;ll be attending the Microsoft Ignite event in Atlanta, as I was lucky enough to be invited to speak this year!\nSo if you\u0026rsquo;re at Ignite, check out the Storage Spaces Direct talks and you might see me hanging round.\n","date":"24 September 2016","externalUrl":null,"permalink":"/2016/09/time-for-another-tech-blog/","section":"Posts","summary":"I’ve decided it’s time to get more active online and give back to the community. Blogs have been my biggest source of information, so I’m committing to sharing gotchas and learnings that might help others.","title":"Time for another Tech Blog","type":"posts"},{"content":"","externalUrl":null,"permalink":"/authors/","section":"Authors","summary":"","title":"Authors","type":"authors"},{"content":"","externalUrl":null,"permalink":"/","section":"Home","summary":"","title":"Home","type":"page"},{"content":"","externalUrl":null,"permalink":"/pages/","section":"Pages","summary":"","title":"Pages","type":"pages"}]