<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://dfinke.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://dfinke.github.io/" rel="alternate" type="text/html" /><updated>2025-10-05T16:56:41+00:00</updated><id>https://dfinke.github.io/feed.xml</id><title type="html">Researching the optimal; implementing the practical</title><subtitle>Contact Doug with your automation needs email finked@hotmail.com</subtitle><entry><title type="html">Build AI Agents That Actually Do Things: PowerShell Function Calling in Action</title><link href="https://dfinke.github.io/powershell/ai/agents/function-calling/2025/10/05/Agent-Framework-Demos-Function-Calling-using-PowerShell-refined.html" rel="alternate" type="text/html" title="Build AI Agents That Actually Do Things: PowerShell Function Calling in Action" /><published>2025-10-05T09:00:00+00:00</published><updated>2025-10-05T09:00:00+00:00</updated><id>https://dfinke.github.io/powershell/ai/agents/function-calling/2025/10/05/Agent-Framework-Demos-Function-Calling-using-PowerShell-refined</id><content type="html" xml:base="https://dfinke.github.io/powershell/ai/agents/function-calling/2025/10/05/Agent-Framework-Demos-Function-Calling-using-PowerShell-refined.html"><![CDATA[<h2 id="what-if-your-ai-agent-could-actually-execute-commands">What if Your AI Agent Could Actually Execute Commands?</h2>

<p>Imagine asking an AI “What’s the weather in London, Paris, and Tokyo?” and watching it automatically call real functions, fetch live data, and give you formatted results. No hardcoded responses, no manual scripting – just intelligent function execution.</p>

<p><strong>That’s exactly what we’re building today.</strong> Using just 7 lines of PowerShell and the PSAI framework, you’ll create an AI agent that can execute your existing functions, cmdlets, and APIs on demand.</p>

<blockquote>
  <p><strong>Why This Matters:</strong> Most AI demos show chatbots that can only talk. This tutorial shows you how to build agents that can <em>do</em> – turning conversation into action.</p>
</blockquote>

<p><a href="#building-the-weather-agent-from-function-to-ai-in-minutes">Jump to the action →</a> or <a href="#getting-started-5-minute-setup">set up your environment first →</a></p>

<h2 id="building-the-weather-agent-from-function-to-ai-in-minutes">Building the Weather Agent: From Function to AI in Minutes</h2>

<p><strong>Here’s the magic:</strong> Take any PowerShell function you’ve already written, pass it to an AI agent, and suddenly your function becomes conversationally accessible. No API wrappers, no complex integrations – just pure PowerShell power.</p>

<p>Let’s start with a simple weather function that calls a free weather API:</p>

<h3 id="-the-psai-advantage">🚀 <strong>The PSAI Advantage</strong></h3>
<blockquote>
  <p><strong>Use What You Already Have:</strong> PSAI works with your existing PowerShell functions, built-in cmdlets, and third-party modules. No rewrites, no wrappers – just instant AI integration.</p>

  <p><strong>Zero Learning Curve:</strong> If you know PowerShell, you know how to build AI agents. The framework does the heavy lifting.</p>
</blockquote>

<h3 id="the-powershell-function-just-7-lines">The PowerShell Function: Just 7 Lines</h3>

<p><strong>This is all it takes.</strong> A basic PowerShell function that calls a weather API – nothing fancy, nothing complicated:</p>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kr">function</span><span class="w"> </span><span class="nn">global</span><span class="p">:</span><span class="nf">Get-Weather</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="kr">param</span><span class="p">(</span><span class="w">
        </span><span class="p">[</span><span class="n">string</span><span class="p">]</span><span class="nv">$location</span><span class="w">
    </span><span class="p">)</span><span class="w">

    </span><span class="n">Invoke-RestMethod</span><span class="w"> </span><span class="nt">-Uri</span><span class="w"> </span><span class="s2">"http://wttr.in/</span><span class="si">$(</span><span class="nv">$location</span><span class="si">)</span><span class="s2">?format=%l:+%c+%t+%h+%w+%p"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<h3 id="test-drive-see-it-work">Test Drive: See It Work</h3>

<p>Before we make it AI-powered, let’s see our simple function in action. Copy the function above into your PowerShell session and try it out:</p>

<p><em>Getting weather for multiple cities at once:</em></p>

<p><img src="/images/posts/AgentFrameworkDemo/GetWeather.png" alt="image" /></p>

<h3 id="the-magic-moment-function--ai-agent">The Magic Moment: Function → AI Agent</h3>

<p><strong>Here’s where it gets interesting.</strong> With your <code class="language-plaintext highlighter-rouge">Get-Weather</code> function loaded in your PowerShell session, you’re one line away from an AI agent that can intelligently call it.</p>

<p><em>From simple function to conversational AI:</em></p>

<p><img src="/images/posts/AgentFrameworkDemo/WeatherAgent.png" alt="image" /></p>

<h3 id="the-one-liner-that-changes-everything">The One-Liner That Changes Everything</h3>

<p><strong>This single line transforms your function into a conversational AI:</strong></p>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">New-Agent</span><span class="w"> </span><span class="nt">-Tools</span><span class="w"> </span><span class="nx">Get-Weather</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">Start-Conversation</span><span class="w">
</span></code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">-Tools</code> parameter specifies the functions or cmdlets that the agent can use during the conversation. It can take multiple tools as a comma-separated list. This gives your agent access to a variety of skill/capabilities. <code class="language-plaintext highlighter-rouge">Start-Conversation</code> begins the interaction with the agent.</p>

<p>This spins up a loop that listens for your input, passing it to the agent as a prompt, it includes the tool <code class="language-plaintext highlighter-rouge">Get-Weather</code> (converted to the function call schema for AI models).</p>

<p>AI determines from the prompt if an external function call is needed. The AI model <strong><em>does not</em></strong> call functions directly; instead, it generates a function call request that the agent framework interprets and executes. It does a <code class="language-plaintext highlighter-rouge">remote procedure call</code>, if you will, to the function. It informs the agent framework the name of the function to call, <code class="language-plaintext highlighter-rouge">Get-Weather</code>, and the parameters they need to be set and to what value <code class="language-plaintext highlighter-rouge">location='nyc'</code>.</p>

<p>The agent framework then executes the function and returns the result to the AI model, which determines if it has enough information to respond or if it needs to make additional function calls. In this case it has enough information and replies with the weather and conditins for New York City (note: the AI model turned <code class="language-plaintext highlighter-rouge">'nyc'</code> into <code class="language-plaintext highlighter-rouge">'New York City'</code>).</p>

<p>Let’s dive deeper with a more complex example that shows the agent’s true intelligence.</p>

<h2 id="watch-the-ai-think-behind-the-scenes-function-calling">Watch the AI Think: Behind-the-Scenes Function Calling</h2>

<p><strong>Want to see the magic happen?</strong> Add the <code class="language-plaintext highlighter-rouge">-ShowToolCalls</code> switch to watch your agent make decisions in real-time. You’ll see exactly when and how it chooses to call your functions.</p>

<p><strong>The Beautiful Part:</strong> The agent doesn’t use hardcoded if/then logic. It genuinely <em>understands</em> when your functions are needed and figures out the right parameters to use.</p>

<!-- TODO: rename image and update path -->
<p><img src="/images/posts/AgentFrameworkDemo/Agent-ShowToolCalls-Many-Locations.png" alt="image" /></p>

<!-- 
New-Agent -Tools Get-Weather -ShowToolCalls | Start-Conversation
😎 : current temp in nyc  london  paris  brazil
VERBOSE: Get-Weather {"location":"New York City"}
VERBOSE: Get-Weather {"location":"London"}
VERBOSE: Get-Weather {"location":"Paris"}
VERBOSE: Get-Weather {"location":"Brazil"}
╭ Agent Response ───────────────────────────────────────────────╮
│ Here are the current temperatures in the requested locations: │
│                                                               │
│ - **New York City**: ☀️ +68°F, 73% humidity, wind 2 mph       │
│ - **London**: 🌧️ +61°F, 48% humidity, wind 15 mph             │
│ - **Paris**: 🌦️ +63°F, 48% humidity, wind 11 mph              │
│ - **Brazil**: ☀️ +93°F, 22% humidity, wind 7 mph              │
│                                                              │
│ Let me know if you need more information!                     │
╰───────────────────────────────────────────────────────────────╯
╭ Next Steps ──────────────────────────────────────╮
│ Follow up, Enter to copy & quit, Ctrl+C to quit. │
╰──────────────────────────────────────────────────╯
 -->

<h3 id="lets-break-it-down">Let’s Break It Down</h3>

<p>The <code class="language-plaintext highlighter-rouge">-ShowToolCalls</code> parameter enables verbose output that reveals the agent’s “thought process.” Watch as it:</p>

<ol>
  <li><strong>Analyzes</strong> your question</li>
  <li><strong>Decides</strong> which functions to call</li>
  <li><strong>Determines</strong> the right parameters</li>
  <li><strong>Executes</strong> multiple functions in parallel when needed</li>
</ol>

<p>As the functions calls are executed, the results are returned to the AI model, which then decides if it has enough information to respond or if it needs to make additional function calls. When complete, the agent provides a final response.</p>

<p>### The “Agent Response” box</p>

<p>After all the function calls have been made, and the agent determines it has enough information, the agent compiles the details and presents a coherent response to the user.</p>

<p>Let’s do a follow-up question to see how the agent handles it.</p>

<h3 id="the-follow-up-ai-memory-in-action">The Follow-Up: AI Memory in Action</h3>

<p><strong>Here’s where it gets really impressive.</strong> Since we’re working with an AI agent, let’s test its reasoning abilities.</p>

<!-- TODO: rename image and update path -->
<p><img src="/images/posts/AgentFrameworkDemo/Sweater-Umbrella.png" alt="image" /></p>

<p>I asked: <em>“Do I need a sweater or umbrella for any of them?”</em></p>

<p><strong>Notice what happened:</strong></p>

<p>✅ <strong>Memory:</strong> The agent remembers all previous weather data<br />
✅ <strong>Context Awareness:</strong> It knows it doesn’t need new function calls<br />
✅ <strong>Reasoning:</strong> It analyzes the existing data to provide practical advice</p>

<p><em>This is conversational AI that actually understands context.</em></p>

<h2 id="your-turn-what-will-you-build">Your Turn: What Will You Build?</h2>

<p><strong>The weather agent is just the beginning.</strong> With this foundation, you can create agents for any domain. Here are some ideas to get you started:</p>

<h3 id="-quick-wins-you-can-try-right-now">💡 <strong>Quick Wins You Can Try Right Now:</strong></h3>

<p><strong>File System Agent</strong> – Give your AI eyes and hands for your files:</p>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">New-Agent</span><span class="w"> </span><span class="nt">-Tools</span><span class="w"> </span><span class="nx">Get-Content</span><span class="p">,</span><span class="w"> </span><span class="nx">Get-ChildItem</span><span class="w"> </span><span class="nt">-ShowToolCalls</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">Start-Conversation</span><span class="w">
</span></code></pre></div></div>

<p>Try asking:</p>
<ul>
  <li><em>“What files do you see?”</em> → Agent calls <code class="language-plaintext highlighter-rouge">Get-ChildItem</code></li>
  <li><em>“Read config.json”</em> → Agent calls <code class="language-plaintext highlighter-rouge">Get-Content</code></li>
  <li><em>“Show me all .log files”</em> → Agent intelligently filters results</li>
</ul>

<p><strong>🔥 Pro Tip:</strong> Add <code class="language-plaintext highlighter-rouge">Set-Content</code> to create a file-writing agent, but implement guardrails first!</p>

<h3 id="coming-next"><strong>Coming Next:</strong></h3>
<p>In my next post, I’ll show you how to build agents with write permissions while keeping you in control – including approval workflows and safety guardrails.</p>

<h3 id="more-agent-ideas"><strong>More Agent Ideas:</strong></h3>
<ul>
  <li><strong>System Monitor:</strong> <code class="language-plaintext highlighter-rouge">Get-Process</code>, <code class="language-plaintext highlighter-rouge">Get-Service</code>, <code class="language-plaintext highlighter-rouge">Get-EventLog</code></li>
  <li><strong>Git Helper:</strong> <code class="language-plaintext highlighter-rouge">git status</code>, <code class="language-plaintext highlighter-rouge">git log</code>, custom Git functions</li>
  <li><strong>Database Query Agent:</strong> Your existing database functions</li>
  <li><strong>API Integration Agent:</strong> Any REST API wrapper functions</li>
</ul>

<h2 id="the-future-is-conversational-automation">The Future is Conversational Automation</h2>

<p><strong>You just learned something powerful:</strong> How to bridge the gap between AI conversation and real-world action. With PSAI, your existing PowerShell expertise becomes the foundation for intelligent automation.</p>

<p><strong>What We Covered:</strong>
✅ Turning any PowerShell function into an AI-accessible tool<br />
✅ Building agents that maintain context and memory<br />
✅ Watching AI make intelligent decisions about when to call functions<br />
✅ Creating practical automation that goes beyond simple chatbots</p>

<p><strong>The Big Picture:</strong> This isn’t just about weather APIs. It’s about creating AI agents that can interact with your entire PowerShell ecosystem – your functions, your modules, your workflows.</p>

<p><em>Your automation just got conversational.</em></p>

<!-- 
 ╭ Next Steps ──────────────────────────────────────╮
│ Follow up, Enter to copy & quit, Ctrl+C to quit. │
╰──────────────────────────────────────────────────╯
😎 : do i need a sweater or umbrella for any of them
╭ Agent Response ──────────────────────────────────────────────────────────────╮
│ Based on the current weather conditions:                                     │
│                                                                              │
│ - **New York City**: ☀️ +68°F – **No need for a sweater or umbrella**.      │
│ - **London**: 🌧️ +61°F – **You might need an umbrella** (it's raining).     │
│ - **Paris**: 🌦️ +63°F – **You might need an umbrella** (there's a chance of │
│  rain).                                                                     │
│ - **Brazil**: ☀️ +93°F – **No need for a sweater or umbrella**.             │
│                                                                              │
│ If you have specific plans or a location in mind, let me know!               │
╰──────────────────────────────────────────────────────────────────────────────╯
-->

<h2 id="getting-started-5-minute-setup">Getting Started: 5-Minute Setup</h2>

<p><strong>Ready to build your first AI agent?</strong> Here’s everything you need:</p>

<h3 id="step-1-install-psai-30-seconds">Step 1: Install PSAI (30 seconds)</h3>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Install-Module</span><span class="w"> </span><span class="nt">-Name</span><span class="w"> </span><span class="nx">PSAI</span><span class="w"> 
</span></code></pre></div></div>

<p>⭐ <strong>Love this project?</strong> Star the repo: <a href="https://github.com/dfinke/PSAI">github.com/dfinke/PSAI</a></p>

<h3 id="step-2-get-your-openai-api-key-5-minutes">Step 2: Get Your OpenAI API Key (5 minutes)</h3>

<p><strong>Quick Setup:</strong></p>

<ol>
  <li><strong>Create Account:</strong> <a href="https://platform.openai.com">platform.openai.com</a> → Verify email &amp; phone</li>
  <li><strong>Add Billing:</strong> Minimum $5 (pay-as-you-go, no overages)</li>
  <li><strong>Generate API Key:</strong> <a href="https://platform.openai.com/account/api-keys">platform.openai.com/account/api-keys</a></li>
</ol>

<p>💰 <strong>Cost Reality Check:</strong> Basic testing costs pennies. The weather examples above cost less than $0.01 to run.</p>

<h3 id="step-3-configure--test-2-minutes">Step 3: Configure &amp; Test (2 minutes)</h3>

<p><strong>Set your API key</strong> (add to your PowerShell <code class="language-plaintext highlighter-rouge">$PROFILE</code>):</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$</span><span class="nn">env</span><span class="p">:</span><span class="nv">OPENAI_API_KEY</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">'sk-proj-your_api_key_here'</span><span class="w">
</span></code></pre></div></div>

<p><strong>Verify everything works:</strong></p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">New-Agent</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">Get-AgentResponse</span><span class="w"> </span><span class="s1">'what is the capital of France?'</span><span class="w">
</span></code></pre></div></div>

<p><strong>Expected output:</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>The capital of France is Paris.
</code></pre></div></div>

<p>🎉 <strong>Success!</strong> You’re ready to build AI agents that can execute real PowerShell functions.</p>

<hr />

<p><strong>Next:</strong> Copy the weather function from above and start building your first function-calling agent!</p>]]></content><author><name></name></author><category term="powershell" /><category term="ai" /><category term="agents" /><category term="function-calling" /><category term="PowerShell" /><category term="AI Agents" /><category term="Function Calling" /><category term="Agent Framework" /><category term="Automation" /><category term="APIs" /><summary type="html"><![CDATA[Stop building chatbots that just talk. Learn how to create AI agents that can execute real PowerShell functions, interact with APIs, and automate your workflows with just 7 lines of code.]]></summary></entry><entry><title type="html">Unlocking the Future of Cloud Automation: MCP Integrations You Need to Know About</title><link href="https://dfinke.github.io/ai/mcp/cloud/computing/devops/ai-tools/2025/07/11/MCP-Servers-And-Integrations.html" rel="alternate" type="text/html" title="Unlocking the Future of Cloud Automation: MCP Integrations You Need to Know About" /><published>2025-07-11T21:00:00+00:00</published><updated>2025-07-11T21:00:00+00:00</updated><id>https://dfinke.github.io/ai/mcp/cloud/computing/devops/ai-tools/2025/07/11/MCP-Servers-And-Integrations</id><content type="html" xml:base="https://dfinke.github.io/ai/mcp/cloud/computing/devops/ai-tools/2025/07/11/MCP-Servers-And-Integrations.html"><![CDATA[<p align="center">
    <img src="https://github.com/dfinke/dfinke.github.io/blob/master/images/posts/MCP-Servers-And-Integrations.png?raw=true" alt="MCP Servers and Integrations" width="600" />
</p>

<p>Imagine a world where you can seamlessly integrate AI with your cloud infrastructure—no complex setup, no extensive coding. Thanks to Model Context Protocols (MCPs), that world is becoming a reality.</p>

<p>Big tech companies are rolling out these integrations, allowing developers to automate tasks, streamline operations, and tap into the full potential of AI-powered workflows. In this post, I’ll dive deep into the MCPs offered by top players like AWS, Google, and Microsoft, giving you the tools you need to stay ahead of the curve.</p>

<p>Let’s explore how these integrations are revolutionizing cloud infrastructure and transforming the way developers work.</p>

<h2 id="mcp-servers-and-integrations">MCP-Servers-And-Integrations</h2>

<table>
  <thead>
    <tr>
      <th><strong>Company/Developer</strong></th>
      <th><strong>MCP Integration Name</strong></th>
      <th><strong>Description</strong></th>
      <th><strong>Source / Code Link</strong></th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>Amazon AWS</strong></td>
      <td><strong>AWS MCP Servers</strong></td>
      <td>Specialized MCP servers that bring AWS best practices directly into your development workflow.</td>
      <td><a href="https://github.com/awslabs/mcp">GitHub – AWS Labs (awslabs/mcp)</a></td>
    </tr>
    <tr>
      <td><strong>Microsoft</strong></td>
      <td><strong>Azure MCP Server</strong></td>
      <td>Gives MCP clients access to key Azure services and tools (Storage, Cosmos DB, CLI, etc.).</td>
      <td><a href="https://github.com/Azure/azure-mcp">GitHub – Azure (Azure/azure-mcp)</a></td>
    </tr>
    <tr>
      <td><strong>Google Cloud</strong></td>
      <td><strong>Google Cloud Run</strong></td>
      <td>Enables AI agents to deploy code to Google Cloud Run.</td>
      <td><a href="https://github.com/GoogleCloudPlatform/cloud-run-mcp">GitHub – GoogleCloudPlatform (cloud-run-mcp)</a></td>
    </tr>
    <tr>
      <td><strong>Alibaba Cloud</strong></td>
      <td><strong>DataWorks MCP Server</strong></td>
      <td>Allows AI to interact with Alibaba Cloud’s DataWorks OpenAPI for seamless cloud resource operations.</td>
      <td><a href="https://github.com/aliyun/alibabacloud-dataworks-mcp-server">GitHub – Alibaba Cloud (dataworks-mcp-server)</a></td>
    </tr>
    <tr>
      <td><strong>Cloudflare</strong></td>
      <td><strong>Cloudflare MCP Server</strong></td>
      <td>Deploy, configure, and manage resources on Cloudflare’s developer platform (Workers, KV, R2, D1).</td>
      <td><a href="https://github.com/cloudflare/mcp-server-cloudflare">GitHub – Cloudflare (cloudflare-mcp-server)</a></td>
    </tr>
    <tr>
      <td><strong>MongoDB, Inc.</strong></td>
      <td><strong>MongoDB MCP Server</strong></td>
      <td>Supports both MongoDB Community Server and Atlas (cloud) for database queries.</td>
      <td><a href="https://github.com/mongodb-js/mongodb-mcp-server">GitHub – mongodb-js (mongodb-mcp-server)</a></td>
    </tr>
    <tr>
      <td><strong>Neon (NeonTech)</strong></td>
      <td><strong>Neon Postgres MCP</strong></td>
      <td>Interact with Neon’s serverless Postgres database platform.</td>
      <td><a href="https://github.com/neondatabase-labs/mcp-server-neon">GitHub – Neon Database (neondatabase-labs/mcp-server-neon)</a></td>
    </tr>
    <tr>
      <td><strong>ClickHouse, Inc.</strong></td>
      <td><strong>ClickHouse MCP</strong></td>
      <td>Enables natural-language queries against a ClickHouse analytics database server.</td>
      <td><a href="https://github.com/ClickHouse/mcp-clickhouse">GitHub – ClickHouse (ClickHouse/mcp-clickhouse)</a></td>
    </tr>
    <tr>
      <td><strong>Upstash</strong></td>
      <td><strong>Upstash (Redis) MCP</strong></td>
      <td>Manage Redis databases and run Redis commands on Upstash via natural language.</td>
      <td><a href="https://github.com/upstash/mcp-server">GitHub – Upstash (mcp-server)</a></td>
    </tr>
    <tr>
      <td><strong>CircleCI</strong></td>
      <td><strong>CircleCI MCP Server</strong></td>
      <td>Allows AI agents to identify and fix build failures on CircleCI continuous integration.</td>
      <td><a href="https://github.com/CircleCI-Public/mcp-server-circleci">GitHub – CircleCI (mcp-server)</a></td>
    </tr>
    <tr>
      <td><strong>Bitrise</strong></td>
      <td><strong>Bitrise MCP Server</strong></td>
      <td>Chat with your CI/CD builds and perform build and app management operations on Bitrise.</td>
      <td><a href="https://github.com/bitrise-io/bitrise-mcp">GitHub – Bitrise (mcp-server)</a></td>
    </tr>
    <tr>
      <td><strong>BrowserStack</strong></td>
      <td><strong>BrowserStack MCP</strong></td>
      <td>Access BrowserStack’s cloud testing platform to debug tests, run accessibility checks, and more.</td>
      <td><a href="https://github.com/browserstack/mcp-server">GitHub – BrowserStack (mcp-server)</a></td>
    </tr>
    <tr>
      <td><strong>Atlassian</strong></td>
      <td><strong>Atlassian Remote MCP</strong></td>
      <td>Securely interact with Jira work items and Confluence pages, with search across both.</td>
      <td><a href="https://www.atlassian.com/platform/remote-mcp-server">Atlassian – Remote MCP Server Docs</a></td>
    </tr>
    <tr>
      <td><strong>Twilio</strong></td>
      <td><strong>Twilio MCP Tools</strong></td>
      <td>Interact with Twilio APIs (send SMS, manage phone numbers, configure account settings, etc.).</td>
      <td><a href="https://github.com/twilio-labs/mcp">GitHub – Twilio Labs (mcp-server)</a></td>
    </tr>
    <tr>
      <td><strong>Zapier</strong></td>
      <td><strong>Zapier MCP (Beta)</strong></td>
      <td>Connect AI agents to 8,000+ apps instantly through Zapier’s integration platform.</td>
      <td><a href="https://zapier.com/mcp">Zapier – MCP Integration Page</a></td>
    </tr>
    <tr>
      <td><strong>PayPal</strong></td>
      <td><strong>PayPal MCP Server</strong></td>
      <td>PayPal’s official MCP server for integrating PayPal services into AI agents.</td>
      <td><a href="https://mcp.paypal.com">PayPal – MCP Documentation</a></td>
    </tr>
    <tr>
      <td><strong>Xero</strong></td>
      <td><strong>Xero MCP Server</strong></td>
      <td>Interact with your business’s accounting data via Xero’s official MCP server.</td>
      <td><a href="https://github.com/XeroAPI/xero-mcp-server">GitHub – Xero API (mcp-server)</a></td>
    </tr>
    <tr>
      <td><strong>Box, Inc.</strong></td>
      <td><strong>Box MCP Server</strong></td>
      <td>Interact with Box’s intelligent content management platform (Box AI) via MCP.</td>
      <td><a href="https://github.com/box-community/mcp-server-box">GitHub – Box Community (mcp-server)</a></td>
    </tr>
  </tbody>
</table>

<hr />

<p>As the adoption of MCPs accelerates, developers must stay on top of these integrations to leverage the full potential of AI in their cloud environments. The rise of MCPs is set to dramatically simplify the way we build, deploy, and manage cloud resources.</p>

<p>Whether you’re working with AWS, Microsoft Azure, or newer providers like Upstash and Neon, the future is about intelligent automation and seamless integration. Be sure to check out these integrations and start exploring how they can enhance your workflows.</p>

<p>Stay ahead of the curve and embrace the future of cloud computing powered by AI!</p>]]></content><author><name></name></author><category term="ai" /><category term="mcp" /><category term="cloud" /><category term="computing" /><category term="devops" /><category term="ai-tools" /><category term="MCP" /><category term="AI Integration" /><category term="Cloud Computing" /><category term="GitHub" /><category term="DevOps" /><category term="Automation" /><category term="APIs" /><summary type="html"><![CDATA[The world of cloud automation is changing fast. Discover how Model Context Protocol (MCP) integrations are reshaping workflows from big tech companies and empowering developers to take control like never before.]]></summary></entry><entry><title type="html">Dashboard Bot: Turn ChatGPT Into a Dashboard Generator Inside VS Code</title><link href="https://dfinke.github.io/ai/copilot/vscode/dashboards/2025/06/10/dashboard-bot-turn-chatgpt-into-a-dashboard-generator-inside-vs-code.html" rel="alternate" type="text/html" title="Dashboard Bot: Turn ChatGPT Into a Dashboard Generator Inside VS Code" /><published>2025-06-10T09:00:00+00:00</published><updated>2025-06-10T09:00:00+00:00</updated><id>https://dfinke.github.io/ai/copilot/vscode/dashboards/2025/06/10/dashboard-bot-turn-chatgpt-into-a-dashboard-generator-inside-vs-code</id><content type="html" xml:base="https://dfinke.github.io/ai/copilot/vscode/dashboards/2025/06/10/dashboard-bot-turn-chatgpt-into-a-dashboard-generator-inside-vs-code.html"><![CDATA[<p align="center">
    <img src="/images/posts/dashboardBot.png" alt="alt text" width="350" />
</p>

<h2 id="-turn-chatgpt-into-a-dashboard-generator-right-inside-your-favorite-ide--vs-code--with-chatmodemd">🚀 Turn ChatGPT into a Dashboard Generator Right Inside Your Favorite IDE — VS Code — with <code class="language-plaintext highlighter-rouge">chatMode.md</code></h2>

<p>Ever wish ChatGPT <em>just knew</em> how to build dashboards without having to spell it out every time?</p>

<p>With <strong>Custom Chat Modes</strong> in <strong>GitHub Copilot Chat for VS Code</strong>, now it can.</p>

<p>You define the personality and behavior — and Copilot does the rest. No wrappers. No extensions. Just a markdown file and your favorite IDE: <strong>VS Code</strong>.</p>

<p>Let me show you how I built a mode called <strong>📊 Dashboard Bot</strong> — and how you can do the same in under 5 minutes.</p>

<hr />

<h3 id="-whats-chatmodemd">🧠 What’s <code class="language-plaintext highlighter-rouge">chatMode.md</code>?</h3>

<p>It’s a new feature in <strong>Copilot Chat (VS Code Insiders)</strong> that lets you define <strong>your own assistant personas</strong>.</p>

<p>Each <code class="language-plaintext highlighter-rouge">.chatMode.md</code> file becomes a selectable Copilot persona in the chat dropdown — complete with its own tone, purpose, and rules.</p>

<hr />

<h3 id="-meet-dashboard-bot">📊 Meet Dashboard Bot</h3>

<p>Here’s the full <code class="language-plaintext highlighter-rouge">dashboard-bot.chatmode.md</code>:</p>

<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nn">---</span>
<span class="na">description</span><span class="pi">:</span> <span class="s2">"</span><span class="s">📊</span><span class="nv"> </span><span class="s">Dashboard</span><span class="nv"> </span><span class="s">Bot"</span>
<span class="nn">---</span>

You are a helpful assistant that specializes in creating dashboards.

You turn raw data (usually CSV or JSON) into clean, interactive dashboards using:
<span class="p">-</span> <span class="gs">**Single-file HTML**</span> with embedded JavaScript (e.g., Chart.js)
<span class="p">-</span> Optionally styled with Tailwind CSS
<span class="p">-</span> Or React + Recharts if requested

Always ask the user:
<span class="p">-</span> What kind of chart(s) they want (bar, line, pie, etc.)?
<span class="p">-</span> What columns to visualize?
<span class="p">-</span> If they want the output as a single-file HTML page or as a React component?

Your default is:
<span class="p">-</span> A self-contained, single <span class="sb">`.html`</span> file with everything embedded
<span class="p">-</span> Includes example data or explains how to load an external <span class="sb">`.csv`</span> or <span class="sb">`.json`</span> file
<span class="p">-</span> No external build tools required

Your goals:
<span class="p">-</span> Make dashboards easy to preview
<span class="p">-</span> Keep the code clean and copy-pasteable
<span class="p">-</span> Include usage notes or preview instructions when needed

Never overcomplicate it. Avoid frameworks unless explicitly requested.
</code></pre></div></div>

<p>Save that as <code class="language-plaintext highlighter-rouge">dashboard-bot.chatmode.md</code>, open Copilot Chat, and select “📊 Dashboard Bot” from the dropdown. Instantly, you’ve got a dashboard-savvy AI assistant at your command.</p>

<hr />

<h3 id="-setting-up-dashboard-bot-mode">🎯 Setting Up Dashboard Bot Mode</h3>

<p>Once you’ve created your <code class="language-plaintext highlighter-rouge">dashboard-bot.chatmode.md</code> file, here’s how to activate it:</p>

<ol>
  <li>Open the Copilot Chat panel in VS Code (if you haven’t already)</li>
  <li>Look for the dropdown menu at the bottom of the chat panel</li>
  <li>Click on the dropdown — you should see “📊 Dashboard Bot” as one of the options</li>
  <li>Select it, and voilà! You’re now chatting with your specialized dashboard assistant</li>
</ol>

<p align="center">
    <img src="/images/posts/vscode-custom-mode-selection.png" alt="alt text" width="150" />
</p>

<blockquote>
  <p>💡 <strong>Pro Tip:</strong> You can quickly switch between different modes using the dropdown, making it easy to context-switch between different specialized assistants.</p>
</blockquote>

<hr />

<h3 id="️-top-5-prompt-templates-to-get-started">🛠️ Top 5 Prompt Templates to Get Started</h3>

<h4 id="1--builder-template">1. 🔨 Builder Template</h4>

<blockquote>
  <p>“Create a single-file HTML dashboard template that reads <code class="language-plaintext highlighter-rouge">data.csv</code> from the same folder, uses Chart.js, and shows a bar chart. I’ll reuse it.”</p>
</blockquote>

<h4 id="2--monthly-revenue-chart">2. 📈 Monthly Revenue Chart</h4>

<blockquote>
  <p>“I have a CSV with <code class="language-plaintext highlighter-rouge">Date</code> and <code class="language-plaintext highlighter-rouge">Revenue</code>. Create a single HTML file with a bar chart showing monthly revenue.”</p>
</blockquote>

<h4 id="3--sales-breakdown">3. 🥧 Sales Breakdown</h4>

<blockquote>
  <p>“CSV with <code class="language-plaintext highlighter-rouge">Category</code> and <code class="language-plaintext highlighter-rouge">TotalSales</code>. Build a pie chart dashboard showing sales by category.”</p>
</blockquote>

<h4 id="4--multi-series-line-chart">4. 📉 Multi-Series Line Chart</h4>

<blockquote>
  <p>“Line chart with multiple lines — one per region — showing sales over time. Use Chart.js in a single HTML file.”</p>
</blockquote>

<h4 id="5--table--chart-combo">5. 📊 Table + Chart Combo</h4>

<blockquote>
  <p>“Dashboard with both a data table and a bar chart. Columns: <code class="language-plaintext highlighter-rouge">Product</code>, <code class="language-plaintext highlighter-rouge">Units Sold</code>, <code class="language-plaintext highlighter-rouge">Profit</code>. Single HTML file.”</p>
</blockquote>

<hr />

<h3 id="-why-this-is-a-game-changer">🧩 Why This Is a Game Changer</h3>

<ul>
  <li>No more repeating yourself</li>
  <li>Codify prompt behavior like code</li>
  <li>Paves the way for <strong>tool-augmented agents</strong> in the IDE</li>
</ul>

<hr />

<h3 id="-whats-next">💬 What’s Next?</h3>

<p>You could:</p>

<ul>
  <li>Build a <strong>Security Reviewer</strong> that flags risky code</li>
  <li>Build a <strong>Rubber Duck</strong> mode that only asks clarifying questions</li>
  <li>Or plug into your own <strong>MCP toolchain</strong> and get real task automation</li>
</ul>

<p>If you want a GitHub repo with reusable ChatModes, prompt packs, and template dashboards — ping me.</p>

<hr />

<h3 id="️-where-to-put-your-chatmodemd-files">🗂️ Where to Put Your <code class="language-plaintext highlighter-rouge">chatMode.md</code> Files?</h3>

<p>Your custom chat modes need to live in a specific location for VS Code to find them:</p>

<ol>
  <li><strong>Workspace Settings</strong>:
    <ul>
      <li>Create a <code class="language-plaintext highlighter-rouge">.vscode/chat-modes</code> folder in your workspace</li>
      <li>Place your <code class="language-plaintext highlighter-rouge">.chatMode.md</code> files there</li>
      <li>Perfect for project-specific chat modes!</li>
    </ul>
  </li>
  <li><strong>User Settings Location</strong>:
    <ul>
      <li>Windows: <code class="language-plaintext highlighter-rouge">%APPDATA%\Code\User\globalStorage\github.copilot-chat\chat-modes</code></li>
      <li>macOS: <code class="language-plaintext highlighter-rouge">~/Library/Application Support/Code/User/globalStorage/github.copilot-chat/chat-modes</code></li>
      <li>Linux: <code class="language-plaintext highlighter-rouge">~/.config/Code/User/globalStorage/github.copilot-chat/chat-modes</code></li>
    </ul>
  </li>
</ol>

<p>Pro Tip: The workspace location is great for sharing chat modes with your team via source control.</p>

<h3 id="️-quick-access-via-command-palette">⌨️ Quick Access via Command Palette</h3>

<p>You can also manage your chat modes directly through VS Code’s Command Palette:</p>

<ol>
  <li>Press <code class="language-plaintext highlighter-rouge">Ctrl+Shift+P</code> (Windows/Linux) or <code class="language-plaintext highlighter-rouge">Cmd+Shift+P</code> (macOS)</li>
  <li>Type “Chat:”</li>
  <li>Look for these commands:
    <ul>
      <li><code class="language-plaintext highlighter-rouge">Chat: New Mode File</code></li>
      <li><code class="language-plaintext highlighter-rouge">Chat: Set Chat Mode</code></li>
      <li><code class="language-plaintext highlighter-rouge">Chat: Configure Chat Modes</code></li>
    </ul>
  </li>
</ol>

<p>This is the fastest way to create, edit, and switch between your custom chat modes!</p>

<hr />

<h2 id="-conclusion">🎯 Conclusion</h2>

<p>The power of custom chat modes in GitHub Copilot Chat represents a significant leap forward in how we interact with AI assistants. Dashboard Bot is just one example of how we can specialize these tools for specific tasks, making our development workflow more efficient and focused.</p>

<p>By creating your own <code class="language-plaintext highlighter-rouge">.chatMode.md</code> files, you can build AI assistants that perfectly match your needs – whether that’s for dashboard creation, API testing, documentation writing, or any other specialized development task.</p>

<p>The beauty of this approach lies in its simplicity: no complex setups, no external dependencies, just a markdown file that transforms Copilot into your perfect coding companion. As we continue to explore the possibilities of AI-assisted development, custom chat modes will undoubtedly become an essential tool in every developer’s toolkit.</p>

<p>So, what specialized AI assistant will you create?</p>

<hr />

<p><em>Happy Dashboarding! 📊✨</em></p>

<hr />

<h2 id="-stay-connected">🤝 Stay Connected</h2>

<ul>
  <li>X - <a href="https://twitter.com/dfinke">@dfinke</a></li>
  <li>LinkedIn - <a href="https://www.linkedin.com/in/douglasfinke/">douglasfinke</a></li>
  <li>YouTube - <a href="https://www.youtube.com/@DougFinke">@DougFinke</a></li>
  <li>GitHub - <a href="https://github.com/dfinke">dfinke</a></li>
  <li>Blog - <a href="https://dfinke.github.io/">dfinke.github.io</a></li>
</ul>]]></content><author><name></name></author><category term="ai" /><category term="copilot" /><category term="vscode" /><category term="dashboards" /><category term="AI" /><category term="GitHub Copilot" /><category term="VS Code" /><category term="dashboards" /><category term="chatMode" /><category term="productivity" /><summary type="html"><![CDATA[How to create a custom dashboard-generating AI assistant in VS Code using GitHub Copilot Chat's chatMode.md feature.]]></summary></entry><entry><title type="html">I Had the Idea. AI Did the Work</title><link href="https://dfinke.github.io/ai/events/trends/2025/06/07/I-Had-the-Idea-AI-Did-the-Work.html" rel="alternate" type="text/html" title="I Had the Idea. AI Did the Work" /><published>2025-06-07T09:00:00+00:00</published><updated>2025-06-07T09:00:00+00:00</updated><id>https://dfinke.github.io/ai/events/trends/2025/06/07/I-Had-the-Idea-AI-Did-the-Work</id><content type="html" xml:base="https://dfinke.github.io/ai/events/trends/2025/06/07/I-Had-the-Idea-AI-Did-the-Work.html"><![CDATA[<p align="center">
    <img src="/images/posts/GitHubActionsHeader.png" alt="alt text" width="350" />
</p>

<h1 id="one-idea-one-prompt--watching-github-copilot-code-agent-work-in-real-time">One Idea, One Prompt — Watching GitHub Copilot Code Agent Work in Real Time</h1>

<p>I’ve been experimenting with the new GitHub Copilot Code Agent. It’s early, but you can already feel where this is going.</p>

<p>The flow is straightforward:</p>

<ol>
  <li>I create a GitHub Issue describing a task.</li>
  <li>I assign it to Copilot.</li>
  <li>It creates a branch, opens a PR, and triggers a GitHub Action.</li>
</ol>

<p>You can watch the work unfold, piece by piece. But here’s the thing:</p>

<p><strong>I had to keep flipping tabs.</strong></p>
<ul>
  <li>One to check the PR</li>
  <li>Another to check the Actions tab</li>
  <li>Click, scroll, refresh</li>
  <li>Repeat</li>
</ul>

<p>It felt like <em>exactly the kind of friction an agent is supposed to remove.</em></p>

<h2 id="the-original-itch">The Original Itch</h2>

<p>So I had the idea: <strong>I want a live dashboard.</strong></p>
<ul>
  <li>One screen.</li>
  <li>On the left: PRs.</li>
  <li>On the right: Workflow runs.</li>
  <li>Updated every 15 seconds. No reloads. No tab switching.</li>
</ul>

<p>That was part of the original itch—the vision of how this should feel. If we’re going to work with agents, we should have tools that <em>show the agency happening.</em></p>

<h2 id="the-prompt">The Prompt</h2>

<p>I didn’t overthink it. I spun up a completely separate project in VS Code, Copilot enabled.
Different repo, fresh folder. Just UI.</p>

<p>And I prompted:</p>

<blockquote>
  <p>“Create an HTML dashboard that shows all open PRs and their GitHub Actions status. Refresh every 15 seconds.”</p>
</blockquote>

<p>That was it.</p>

<h2 id="the-result">The Result</h2>

<p>Copilot built the whole thing—HTML, JavaScript, CSS. Used the GitHub API.
I plugged in my repo name and a token, saved, and it ran.</p>

<p>And it just worked.</p>

<p><img src="/images/posts/GitHubStatusDashboard.png" alt="alt text" /></p>
<ul>
  <li>PRs are listed on the left.</li>
  <li>Workflow runs on the right.</li>
  <li>Auto-refreshes every 15 seconds.</li>
  <li>I can see the agent’s progress in real time.</li>
</ul>

<p>It’s not fancy. It’s not meant to be.</p>

<p>But it’s <em>exactly</em> what I wanted, and all from a single prompt. I didn’t write a line of code for the dashboard itself and it just works.</p>

<h2 id="the-shift">The Shift</h2>

<p>This is how things are changing:</p>

<ul>
  <li>I didn’t build a dashboard. I had the idea and prompted for it.</li>
  <li>I didn’t wire up backend APIs. The agent did it.</li>
  <li>I didn’t switch contexts. I created one.</li>
</ul>

<p><strong>From building to orchestrating. From tabs to tasks.</strong></p>

<p>The future of development isn’t just AI writing code—it’s reshaping how we <em>observe and direct</em> code being written. The dashboard I prompted into existence is as much about <strong>visibility</strong> as it is about <strong>agency.</strong></p>

<p>And that’s the deeper shift.</p>

<h2 id="whats-next">What’s Next?</h2>

<ul>
  <li>What if the dashboard had a button to reassign failed runs?</li>
  <li>What if it visualized issue threads as intent containers?</li>
  <li>What if it prompted <em>me</em> when something needed attention?</li>
</ul>

<p>This is barely day one.</p>

<p>Agents aren’t just coding—they’re reshaping the workflows around code.
And we’re just getting started.</p>

<h2 id="get-the-code">Get the Code</h2>

<p>Want to try this dashboard yourself? I’ve made the code available in my GitHub repository: <a href="https://github.com/dfinke/github-status-dashboard">github-status-dashboard</a>. Feel free to fork it, modify it, and make it your own.</p>

<p>To get started:</p>
<ol>
  <li>Clone the repository</li>
  <li>Add your GitHub token</li>
  <li>Update the repository name</li>
  <li>Open the HTML file in your browser</li>
</ol>

<p>The code is intentionally simple and straightforward - exactly as it was generated from the prompt. It serves as a great starting point for your own customizations and improvements.</p>

<hr />
<h2 id="connect-with-me">Connect with Me</h2>

<table>
  <thead>
    <tr>
      <th>Doug Finke</th>
      <th> </th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>X (Twitter)</strong></td>
      <td><a href="https://twitter.com/dfinke">@dfinke</a></td>
    </tr>
    <tr>
      <td><strong>LinkedIn</strong></td>
      <td><a href="https://www.linkedin.com/in/douglasfinke/">linkedin.com/in/douglasfinke</a></td>
    </tr>
    <tr>
      <td><strong>YouTube</strong></td>
      <td><a href="https://www.youtube.com/@DougFinke">youtube.com/@DougFinke</a></td>
    </tr>
    <tr>
      <td><strong>GitHub</strong></td>
      <td><a href="https://github.com/dfinke">github.com/dfinke</a></td>
    </tr>
    <tr>
      <td><strong>Blog</strong></td>
      <td><a href="https://dfinke.github.io">dfinke.github.io</a></td>
    </tr>
  </tbody>
</table>]]></content><author><name></name></author><category term="ai" /><category term="events" /><category term="trends" /><category term="AI" /><category term="events" /><category term="trends" /><category term="mcp" /><category term="powershell" /><summary type="html"><![CDATA[One Idea, One Prompt — Watching GitHub Copilot Work in Real Time]]></summary></entry><entry><title type="html">PowerShell Quiz: Understanding Closures in Loops</title><link href="https://dfinke.github.io/powershell,%20closures,%20scripting,%20quiz/2025/04/23/powershell-closures-gotcha.html" rel="alternate" type="text/html" title="PowerShell Quiz: Understanding Closures in Loops" /><published>2025-04-23T06:30:00+00:00</published><updated>2025-04-23T06:30:00+00:00</updated><id>https://dfinke.github.io/powershell,%20closures,%20scripting,%20quiz/2025/04/23/powershell-closures-gotcha</id><content type="html" xml:base="https://dfinke.github.io/powershell,%20closures,%20scripting,%20quiz/2025/04/23/powershell-closures-gotcha.html"><![CDATA[<p><img src="/images/posts/2025-04-22-powershell-closures-gotcha.png" alt="alt text" /></p>

<p>Have you ever hit a surprising result in PowerShell where functions inside a loop don’t behave like you expect? Let’s dig into this classic gotcha.</p>

<p>Here’s the snippet:</p>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$funcs</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">@()</span><span class="w">

</span><span class="kr">foreach</span><span class="w"> </span><span class="p">(</span><span class="nv">$i</span><span class="w"> </span><span class="kr">in</span><span class="w"> </span><span class="mi">1</span><span class="o">..</span><span class="mi">3</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nv">$funcs</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nv">$i</span><span class="w"> </span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">

</span><span class="n">Write-Host</span><span class="w"> </span><span class="p">((</span><span class="nv">$funcs</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">ForEach-Object</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="o">&amp;</span><span class="bp">$_</span><span class="w"> </span><span class="p">})</span><span class="w"> </span><span class="o">-join</span><span class="w"> </span><span class="s1">', '</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>

<p>The quiz gives four possible outcomes:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>A. 0, 1, 2  
B. 1, 2, 3  
C. 3, 3, 3  
D. Error  
</code></pre></div></div>

<hr />

<h2 id="-step-by-step-breakdown">🔍 Step-by-Step Breakdown</h2>

<h3 id="step-1-initializing-the-array">Step 1: Initializing the array</h3>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$funcs</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">@()</span><span class="w">
</span></code></pre></div></div>

<p>We’re setting up an empty array to hold script blocks (PowerShell’s anonymous functions).</p>

<hr />

<h3 id="step-2-the-loop">Step 2: The loop</h3>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kr">foreach</span><span class="w"> </span><span class="p">(</span><span class="nv">$i</span><span class="w"> </span><span class="kr">in</span><span class="w"> </span><span class="mi">1</span><span class="o">..</span><span class="mi">3</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nv">$funcs</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nv">$i</span><span class="w"> </span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p>This adds <strong>three</strong> script blocks to the array. Each of them references the variable <code class="language-plaintext highlighter-rouge">$i</code>.</p>

<p>But here’s the catch: <strong>PowerShell closures capture the variable, not its current value</strong>. By the time the loop finishes, <code class="language-plaintext highlighter-rouge">$i</code> equals <code class="language-plaintext highlighter-rouge">3</code>. So <strong>all three script blocks return <code class="language-plaintext highlighter-rouge">3</code></strong> when invoked.</p>

<hr />

<h3 id="step-3-executing-the-script-blocks">Step 3: Executing the script blocks</h3>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$funcs</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">ForEach-Object</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="o">&amp;</span><span class="bp">$_</span><span class="w"> </span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p>We run each script block. Since they all reference the same <code class="language-plaintext highlighter-rouge">$i</code>, they all return <code class="language-plaintext highlighter-rouge">3</code>.</p>

<hr />

<h3 id="step-4-joining-the-output">Step 4: Joining the output</h3>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">-join</span><span class="w"> </span><span class="s1">', '</span><span class="w">
</span></code></pre></div></div>

<p>Result:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>3, 3, 3
</code></pre></div></div>

<hr />

<h2 id="-correct-answer-c-3-3-3">✅ Correct Answer: <strong>C. 3, 3, 3</strong></h2>

<hr />

<h2 id="-the-fix-capture-the-value-not-the-reference">🛠 The Fix: Capture the value, not the reference</h2>

<p>PowerShell gives you a built-in way to capture the <em>current</em> value of a variable into a closure:</p>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kr">foreach</span><span class="w"> </span><span class="p">(</span><span class="nv">$i</span><span class="w"> </span><span class="kr">in</span><span class="w"> </span><span class="mi">1</span><span class="o">..</span><span class="mi">3</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nv">$funcs</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nv">$i</span><span class="w"> </span><span class="p">}</span><span class="o">.</span><span class="nf">GetNewClosure</span><span class="p">()</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p>Now each script block holds onto its own snapshot of <code class="language-plaintext highlighter-rouge">$i</code>.</p>

<p>So this:</p>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Write-Host</span><span class="w"> </span><span class="p">((</span><span class="nv">$funcs</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">ForEach-Object</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="o">&amp;</span><span class="bp">$_</span><span class="w"> </span><span class="p">})</span><span class="w"> </span><span class="o">-join</span><span class="w"> </span><span class="s1">', '</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>

<p>will output:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>1, 2, 3
</code></pre></div></div>

<hr />

<h2 id="-takeaway">🧠 Takeaway</h2>

<p>Closures are powerful, but they can surprise you. Remember:</p>

<blockquote>
  <p><strong>In PowerShell, <code class="language-plaintext highlighter-rouge">{ $i }</code> captures the variable — not the value. Use <code class="language-plaintext highlighter-rouge">.GetNewClosure()</code> to freeze the value at that moment.</strong></p>
</blockquote>

<p>Got more PowerShell puzzles? Drop them in the comments or <a href="https://www.meetup.com/NycPowershellMeetup/">join the NYC PowerShell Meetup</a>!</p>]]></content><author><name></name></author><category term="PowerShell, Closures, Scripting, Quiz" /><category term="PowerShell, Closures, Scripting, Quiz" /><summary type="html"><![CDATA[PowerShell-Quiz-Understanding-Closures-in-Loops]]></summary></entry><entry><title type="html">Leveraging AI-Driven Automation in PowerShell</title><link href="https://dfinke.github.io/powershell%20psai/2025/02/04/Leveraging-AI-Driven-Automation-in-PowerShell.html" rel="alternate" type="text/html" title="Leveraging AI-Driven Automation in PowerShell" /><published>2025-02-04T07:00:00+00:00</published><updated>2025-02-04T07:00:00+00:00</updated><id>https://dfinke.github.io/powershell%20psai/2025/02/04/Leveraging-AI-Driven%20Automation%20in%20PowerShell</id><content type="html" xml:base="https://dfinke.github.io/powershell%20psai/2025/02/04/Leveraging-AI-Driven-Automation-in-PowerShell.html"><![CDATA[<div style="text-align: center;">
    <img src="https://raw.githubusercontent.com/dfinke/dfinke.github.io/master/images/posts/Leverage-AI-PowerShell/00-Leverage-AI-PowerShell.png" width="400" height="300" />
</div>

<p><br />
<br /></p>

<h2 id="introduction">Introduction</h2>
<p>In today’s fast-paced IT landscape, automation is no longer a luxury but a necessity. As PowerShell continues to be the backbone of Windows administration, integrating artificial intelligence (AI) into scripting can significantly enhance productivity. Enter PSAI, the PowerShell AI module—a powerful tool that streamlines automation, scripting, and command execution using AI-driven assistance.</p>

<h2 id="the-evolution-of-powershell-and-ai">The Evolution of PowerShell and AI</h2>

<p>PowerShell has evolved from a simple scripting language into a robust automation platform. The integration of AI tools like OpenAI models into PowerShell scripting has unlocked new efficiencies, making it easier than ever to generate scripts, analyze logs, and troubleshoot systems.
PSAI takes this concept further by embedding AI-powered assistance directly into the PowerShell environment. By leveraging natural language processing (NLP), it allows administrators and developers to describe tasks in plain English and receive functional PowerShell code in response.</p>

<h2 id="getting-started-with-psai">Getting Started with PSAI</h2>
<p>PSAI is designed to be easily integrated into any PowerShell environment. Installing it is straightforward:
Install-Module -Name PSAI
Once installed, users can begin leveraging AI to assist with various administrative and development tasks.</p>

<h2 id="obtaining-an-openai-api-key">Obtaining an OpenAI API Key</h2>
<p>To fully utilize PSAI, users need an OpenAI API key. Obtaining a key is a simple process:</p>
<ol>
  <li>Visit OpenAI’s API platform.</li>
  <li>Sign up for an account or log in if you already have one.</li>
  <li>Navigate to the API section and generate a new API key.</li>
  <li>Store the key securely, as it will be required for authentication.
OpenAI’s API operates on a credit-based system, and it is safe to use a credit card to purchase API credits. OpenAI provides transparency in usage, ensuring that users only pay for what they consume.</li>
</ol>

<h2 id="key-features-of-psai">Key Features of PSAI</h2>
<h3 id="ai-generated-scripting">AI-Generated Scripting</h3>
<p>Gone are the days of painstakingly writing PowerShell scripts line by line. PSAI empowers users with the ability to dynamically generate scripts tailored to their needs. Take the example below. In response to a query like q ‘what is my ip’, PSAI leverages its AI-driven capabilities to suggest the appropriate command:</p>

<p><img src="/images/posts/Leverage-AI-PowerShell/01-Leverage-AI-PowerShell.png" alt="alt text" /></p>

<p>The tool goes beyond merely generating the command. It provides actionable next steps to streamline your workflow, such as copying the command to the clipboard for immediate use. This approach saves time, reduces errors, and enhances productivity for both seasoned professionals and beginners alike.
PSAI’s AI-driven scripting allows users to bypass manual research, focusing instead on implementing solutions directly.</p>

<h3 id="follow-up-with-contextual-awareness">Follow-Up with Contextual Awareness</h3>
<p>What sets PSAI apart is its ability to retain conversational context, much like a chat assistant. The “Follow Up” feature ensures that subsequent queries build on prior interactions, enabling a more cohesive and intuitive experience. For instance, if you run a command and then ask for additional steps or refinements, PSAI can interpret your request in context without requiring repetitive input.
This memory-like functionality significantly reduces the cognitive load on users, allowing them to focus on outcomes rather than the intricacies of scripting.</p>

<h3 id="seamless-contextual-refinements">Seamless Contextual Refinements</h3>
<p>PSAI truly shines when users need to refine their queries or add qualifying information. With its ability to retain context, PSAI can provide intelligent follow-ups without requiring redundant explanations.
For instance:</p>
<ol>
  <li>The user asks, q ‘processes using more than 800 handles’. PSAI generates the PowerShell.</li>
  <li>The user then asks for additional refinement: owned by Microsoft. PSAI understands the context and modifies the command.</li>
</ol>

<p><img src="/images/posts/Leverage-AI-PowerShell/02-Leverage-AI-PowerShell.png" alt="alt text" /></p>

<p>This example highlights PSAI’s ability to adapt dynamically to follow-up questions, saving users time and effort by maintaining a thread of understanding throughout the interaction. Such contextual awareness elevates the scripting experience, making it both intuitive and efficient.</p>

<h3 id="automated-reporting-made-effortless">Automated Reporting Made Effortless</h3>
<p>PSAI also simplifies tasks that typically require detailed knowledge of PowerShell scripting. For example, to generate a report of all users with administrative privileges and export it to a CSV file, the user can simply ask.</p>

<p><img src="/images/posts/Leverage-AI-PowerShell/03-Leverage-AI-PowerShell.png" alt="alt text" /></p>

<p>PSAI instantly provides the appropriate command. This feature is invaluable for automating administrative tasks, enabling users to generate reports or handle complex operations with minimal effort. Once again, the “Follow Up” functionality remains available, allowing users to refine the output further if necessary.</p>

<h3 id="autonomous-agents-for-complex-workflows">Autonomous Agents for Complex Workflows</h3>
<p>One of PSAI’s most powerful features is the ability to create autonomous agents for performing complex workflows. Using the New-Agent cmdlet, users can define agents equipped with specific tools, instructions, and verbose logging for advanced control.</p>

<p>Consider the following scenario:</p>

<p><img src="/images/posts/Leverage-AI-PowerShell/04-Leverage-AI-PowerShell.png" alt="alt text" /></p>

<p>Here’s what makes this remarkable:</p>
<ol>
  <li>Agent Creation: The New-Agent cmdlet creates an agent capable of leveraging the New-TavilyAITool for web searches.</li>
  <li>Instructions: A string, interpolated using PowerShell’s syntax, passes dynamic information (e.g., the current date) to the agent.</li>
  <li>Verbose Logging: With -ShowToolCalls, PSAI provides visibility into the AI’s decision-making process. In this example, the VERBOSE output reveals the specific functions (Invoke-WebSearch) and parameters used.</li>
</ol>

<p>As the workflow unfolds, the AI evaluates the results of each web search, determining whether further steps are needed or if it can conclude. The final output is a structured report of U.S. job numbers over the last three Decembers, automatically aggregated and presented for the user.</p>

<h2 id="the-future-of-ai-in-powershell-automation">The Future of AI in PowerShell Automation</h2>
<p>The integration of AI into PowerShell through tools like PSAI marks a turning point in how professionals approach scripting, automation, and complex workflows. The ability to generate scripts dynamically, retain conversational context, and refine outputs on the fly has already transformed productivity for many users. However, the introduction of autonomous agents takes this potential to the next level.</p>

<p>With features like <code class="language-plaintext highlighter-rouge">New-Agent</code>, users can create intelligent, task-specific agents equipped with tools and instructions to handle intricate, multi-step operations autonomously. These agents can interpret high-level directives, leverage external tools (like web searches), and dynamically adjust their workflows based on the results they retrieve. This combination of AI-driven intelligence and automation empowers users to tackle complex scenarios with minimal manual intervention.</p>

<p>As PSAI continues to evolve, its capacity for integrating advanced AI capabilities, such as better decision-making, real-time contextual awareness, and enhanced transparency through verbose logging, will only grow. This future of AI in PowerShell is not just about automation—it’s about creating intelligent systems that collaborate with users to solve problems efficiently and effectively.</p>

<h2 id="conclusion">Conclusion</h2>

<p>PSAI represents a paradigm shift in PowerShell automation, blending traditional scripting capabilities with cutting-edge AI-driven functionalities. From dynamically generating scripts to refining complex queries and deploying autonomous agents, PSAI enables users to achieve unprecedented levels of efficiency and accuracy.</p>

<p>The examples highlighted in this article demonstrate PSAI’s versatility: automating administrative reporting, refining contextual queries, and managing intricate workflows with autonomous agents. These features empower IT professionals, system administrators, and developers to focus on solving problems rather than getting bogged down in the mechanics of scripting.</p>

<p>As we embrace this new era of AI-powered automation, tools like PSAI will play a pivotal role in reshaping how we interact with technology. The future is here, and it’s making PowerShell more powerful, intuitive, and indispensable than ever before.</p>]]></content><author><name></name></author><category term="PowerShell PSAI" /><category term="PowerShell PSAI" /><summary type="html"><![CDATA[Leveraging AI-Driven Automation in PowerShell]]></summary></entry><entry><title type="html">Introducing a Custom ‘map’ Function in PowerShell for Functional Programming</title><link href="https://dfinke.github.io/search%20engines/2024/11/13/Introducing-a-Custom-map-Function-in-PowerShell-for-Functional-Programming.html" rel="alternate" type="text/html" title="Introducing a Custom ‘map’ Function in PowerShell for Functional Programming" /><published>2024-11-13T05:00:00+00:00</published><updated>2024-11-13T05:00:00+00:00</updated><id>https://dfinke.github.io/search%20engines/2024/11/13/Introducing-a-Custom-map-Function-in-PowerShell-for-Functional-Programming</id><content type="html" xml:base="https://dfinke.github.io/search%20engines/2024/11/13/Introducing-a-Custom-map-Function-in-PowerShell-for-Functional-Programming.html"><![CDATA[<div style="text-align: center;">
    <img src="https://raw.githubusercontent.com/dfinke/dfinke.github.io/master/images/posts/Introducing-a-Custom-map-Function-in-PowerShell-for-Functional-Programming.png" width="300" height="300" />
</div>

<p><br />
<br /></p>

<p>As developers, we’re always looking for ways to write cleaner, more efficient code. One of the paradigms that facilitate this is functional programming, which emphasizes the use of functions and immutability. While PowerShell is primarily an object-oriented scripting language, it also supports functional programming concepts. Recently, I implemented a custom <code class="language-plaintext highlighter-rouge">map</code> function in PowerShell to process multiple arrays in a functional style. In this blog post, I’ll walk you through the implementation and show you how it can be used to simplify your data processing tasks.</p>

<h2 id="the-need-for-a-map-function-in-powershell">The Need for a ‘map’ Function in PowerShell</h2>

<p>In languages like Python and JavaScript, the <code class="language-plaintext highlighter-rouge">map</code> function is a staple for transforming data collections. It applies a given function to each item of a list and returns a list of the results. While PowerShell has cmdlets like <code class="language-plaintext highlighter-rouge">ForEach-Object</code>, they don’t natively support mapping over multiple arrays simultaneously. To bridge this gap, I created a custom <code class="language-plaintext highlighter-rouge">map</code> function that can apply a function to multiple arrays in parallel.</p>

<h2 id="the-implementation">The Implementation</h2>

<p>Here’s the core of the <code class="language-plaintext highlighter-rouge">map</code> function:</p>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kr">function</span><span class="w"> </span><span class="nf">map</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="kr">param</span><span class="p">(</span><span class="w">
        </span><span class="nv">$func</span><span class="p">,</span><span class="w"> 
        </span><span class="p">[</span><span class="n">Parameter</span><span class="p">(</span><span class="n">ValueFromRemainingArguments</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="bp">$true</span><span class="p">)]</span><span class="w"> 
        </span><span class="nv">$arrays</span><span class="w">
    </span><span class="p">)</span><span class="w">

    </span><span class="c"># Ensure all arrays are of the same length</span><span class="w">
    </span><span class="nv">$arrays</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">ForEach-Object</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="kr">if</span><span class="w"> </span><span class="p">(</span><span class="nv">$arrays</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="nf">Length</span><span class="w"> </span><span class="o">-ne</span><span class="w"> </span><span class="bp">$_</span><span class="o">.</span><span class="nf">Length</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
            </span><span class="kr">throw</span><span class="w"> </span><span class="s2">"All arrays must be of the same length"</span><span class="w">
        </span><span class="p">}</span><span class="w">
    </span><span class="p">}</span><span class="w">

    </span><span class="nv">$dataType</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$arrays</span><span class="o">.</span><span class="nf">GetType</span><span class="p">()</span><span class="o">.</span><span class="nf">Name</span><span class="w">

    </span><span class="kr">if</span><span class="w"> </span><span class="p">(</span><span class="nv">$dataType</span><span class="w"> </span><span class="o">-eq</span><span class="w"> </span><span class="s2">"Object[]"</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="c"># If arrays are simple objects, apply the function directly</span><span class="w">
        </span><span class="nv">$arrays</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">ForEach-Object</span><span class="w"> </span><span class="p">{</span><span class="w">
            </span><span class="o">&amp;</span><span class="w"> </span><span class="nv">$func</span><span class="w"> </span><span class="bp">$_</span><span class="w">
        </span><span class="p">}</span><span class="w">
    </span><span class="p">}</span><span class="w"> 
    </span><span class="kr">elseif</span><span class="w"> </span><span class="p">(</span><span class="nv">$dataType</span><span class="w"> </span><span class="o">-eq</span><span class="w"> </span><span class="s1">'List`1'</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="c"># If arrays are lists, process them in parallel</span><span class="w">
        </span><span class="nv">$arrayCount</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$arrays</span><span class="o">.</span><span class="nf">Count</span><span class="w">
        </span><span class="nv">$count</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$arrays</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="nf">Length</span><span class="w">

        </span><span class="c"># Get the parameter names of the function</span><span class="w">
        </span><span class="kr">if</span><span class="w"> </span><span class="p">(</span><span class="nv">$func</span><span class="w"> </span><span class="o">-is</span><span class="w"> </span><span class="p">[</span><span class="n">scriptblock</span><span class="p">])</span><span class="w"> </span><span class="p">{</span><span class="w">
            </span><span class="nv">$funcParams</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$func</span><span class="o">.</span><span class="nf">Ast</span><span class="o">.</span><span class="nf">ParamBlock</span><span class="o">.</span><span class="nf">Parameters</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">ForEach-Object</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="bp">$_</span><span class="o">.</span><span class="nf">Name</span><span class="o">.</span><span class="nf">VariablePath</span><span class="o">.</span><span class="nf">UserPath</span><span class="w"> </span><span class="p">}</span><span class="w">            
        </span><span class="p">}</span><span class="w">
        </span><span class="kr">else</span><span class="w"> </span><span class="p">{</span><span class="w">
            </span><span class="nv">$funcParams</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">Get-Command</span><span class="w"> </span><span class="nv">$func</span><span class="p">)</span><span class="o">.</span><span class="nf">Parameters</span><span class="o">.</span><span class="nf">Keys</span><span class="w"> </span><span class="o">-as</span><span class="w"> </span><span class="p">[</span><span class="n">array</span><span class="p">]</span><span class="w">
        </span><span class="p">}</span><span class="w">

        </span><span class="c"># Iterate over each index and apply the function</span><span class="w">
        </span><span class="kr">for</span><span class="w"> </span><span class="p">(</span><span class="nv">$i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="nv">$i</span><span class="w"> </span><span class="o">-lt</span><span class="w"> </span><span class="nv">$count</span><span class="p">;</span><span class="w"> </span><span class="nv">$i</span><span class="o">++</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">            
            </span><span class="nv">$funcSplat</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="n">ordered</span><span class="p">]@{}</span><span class="w">
            </span><span class="kr">for</span><span class="w"> </span><span class="p">(</span><span class="nv">$ac</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="nv">$ac</span><span class="w"> </span><span class="o">-lt</span><span class="w"> </span><span class="nv">$arrayCount</span><span class="p">;</span><span class="w"> </span><span class="nv">$ac</span><span class="o">++</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
                </span><span class="nv">$funcSplat</span><span class="p">[</span><span class="s2">"</span><span class="si">$(</span><span class="nv">$funcParams</span><span class="p">[</span><span class="nv">$ac</span><span class="p">]</span><span class="si">)</span><span class="s2">"</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$arrays</span><span class="p">[</span><span class="nv">$ac</span><span class="p">][</span><span class="nv">$i</span><span class="p">]</span><span class="w">
            </span><span class="p">}</span><span class="w">

            </span><span class="o">&amp;</span><span class="w"> </span><span class="nv">$func</span><span class="w"> </span><span class="err">@</span><span class="n">funcSplat</span><span class="w">
        </span><span class="p">}</span><span class="w">
    </span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<h3 id="key-features">Key Features</h3>

<ul>
  <li><strong>Parallel Processing</strong>: The function can take multiple arrays and apply a user-defined function to corresponding elements.</li>
  <li><strong>Dynamic Parameter Handling</strong>: It extracts parameter names from the provided script block or function, allowing for flexible argument passing.</li>
  <li><strong>Type Handling</strong>: It checks the data type of the input to ensure proper processing, distinguishing between simple arrays and lists.</li>
</ul>

<h2 id="usage-example">Usage Example</h2>

<p>Let’s see how this function works with a practical example. Suppose we have three arrays containing names, ages, and locations:</p>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$who</span><span class="w">   </span><span class="o">=</span><span class="w"> </span><span class="s1">'John'</span><span class="p">,</span><span class="w"> </span><span class="s1">'Jane'</span><span class="p">,</span><span class="w"> </span><span class="s1">'Doe'</span><span class="p">,</span><span class="w"> </span><span class="s1">'Smith'</span><span class="w">
</span><span class="nv">$age</span><span class="w">   </span><span class="o">=</span><span class="w"> </span><span class="mi">20</span><span class="p">,</span><span class="w"> </span><span class="mi">30</span><span class="p">,</span><span class="w"> </span><span class="mi">40</span><span class="p">,</span><span class="w"> </span><span class="mi">50</span><span class="w">
</span><span class="nv">$where</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">'New York'</span><span class="p">,</span><span class="w"> </span><span class="s1">'California'</span><span class="p">,</span><span class="w"> </span><span class="s1">'Texas'</span><span class="p">,</span><span class="w"> </span><span class="s1">'Florida'</span><span class="w">
</span></code></pre></div></div>

<p>We can use the <code class="language-plaintext highlighter-rouge">map</code> function to combine these arrays into custom objects:</p>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">map</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="kr">param</span><span class="p">(</span><span class="nv">$who</span><span class="p">,</span><span class="w"> </span><span class="nv">$age</span><span class="p">,</span><span class="w"> </span><span class="nv">$where</span><span class="p">)</span><span class="w">

    </span><span class="p">[</span><span class="n">PSCustomObject</span><span class="p">][</span><span class="n">Ordered</span><span class="p">]@{</span><span class="w">
        </span><span class="nx">Name</span><span class="w">     </span><span class="o">=</span><span class="w"> </span><span class="nv">$who</span><span class="w">
        </span><span class="nx">Age</span><span class="w">      </span><span class="o">=</span><span class="w"> </span><span class="nv">$age</span><span class="w">
        </span><span class="nx">Location</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$where</span><span class="w">
    </span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w"> </span><span class="nv">$who</span><span class="w"> </span><span class="nv">$age</span><span class="w"> </span><span class="nv">$where</span><span class="w">
</span></code></pre></div></div>

<h3 id="output">Output:</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Name  Age Location   
----  --- --------   
John   20 New York   
Jane   30 California 
Doe    40 Texas      
Smith  50 Florida    
</code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">map</code> function applies the script block to each set of elements from the arrays (<code class="language-plaintext highlighter-rouge">$who[$i]</code>, <code class="language-plaintext highlighter-rouge">$age[$i]</code>, <code class="language-plaintext highlighter-rouge">$where[$i]</code>) and constructs a custom object with the combined data.</p>

<h2 id="how-it-works">How It Works</h2>

<ol>
  <li><strong>Parameter Extraction</strong>: The function retrieves the parameter names from the provided script block using the Abstract Syntax Tree (AST).</li>
  <li><strong>Length Verification</strong>: It checks that all input arrays are of the same length to avoid index out-of-range errors.</li>
  <li><strong>Function Invocation</strong>: It uses a loop to iterate over the index of the arrays and splats the parameters into the function for each iteration.</li>
</ol>

<h2 id="benefits">Benefits</h2>

<ul>
  <li><strong>Enhanced Readability</strong>: By abstracting the iteration logic, the <code class="language-plaintext highlighter-rouge">map</code> function allows you to focus on the transformation logic.</li>
  <li><strong>Reusability</strong>: You can use the <code class="language-plaintext highlighter-rouge">map</code> function with any number of arrays and any processing logic encapsulated in a script block or function.</li>
  <li><strong>Functional Programming Style</strong>: This approach promotes immutability and pure functions, which can lead to fewer side effects and easier debugging.</li>
</ul>

<h2 id="conclusion">Conclusion</h2>

<p>The custom <code class="language-plaintext highlighter-rouge">map</code> function brings the power of functional programming’s map operation to PowerShell, enabling parallel processing of multiple arrays with ease. By leveraging script blocks and parameter extraction, it provides a flexible tool for data transformation tasks.</p>

<p>If you often find yourself processing multiple related arrays, consider adding this <code class="language-plaintext highlighter-rouge">map</code> function to your toolkit. It can simplify your scripts and make your code more expressive and maintainable.</p>

<p><strong>Happy scripting!</strong></p>]]></content><author><name></name></author><category term="Search Engines" /><category term="Search Engines" /><summary type="html"><![CDATA[PowerShell's custom map function enables functional programming, processing multiple arrays with ease. Simplify your scripts by applying transformations in parallel.]]></summary></entry><entry><title type="html">The Evolution of Search Engines From Archie to OpenAI Search</title><link href="https://dfinke.github.io/search%20engines/archie/openai/2024/11/01/The-Evolution-of-Search-Engines-From-Archie-to-OpenAI-Search.html" rel="alternate" type="text/html" title="The Evolution of Search Engines From Archie to OpenAI Search" /><published>2024-11-01T07:00:00+00:00</published><updated>2024-11-01T07:00:00+00:00</updated><id>https://dfinke.github.io/search%20engines/archie/openai/2024/11/01/The-Evolution-of-Search-Engines-From-Archie-to-OpenAI-Search</id><content type="html" xml:base="https://dfinke.github.io/search%20engines/archie/openai/2024/11/01/The-Evolution-of-Search-Engines-From-Archie-to-OpenAI-Search.html"><![CDATA[<p><img src="/images/posts/The-Evolution-of-Search-Engines-From-Archie-to-OpenAI-Search.png" alt="alt text" /></p>

<p><strong>The Evolution of Search Engines: From Archie to OpenAI Search</strong></p>

<p>The story of search engines is a journey of constant innovation and transformation. It began in 1990 with Archie, a tool that allowed users to search filenames from FTP sites, laying the groundwork for indexing content online. Since then, search engines have evolved drastically, moving from simple keyword-based searches to AI-driven, context-aware experiences. Let’s explore this fascinating evolution and how it has shaped our interaction with the web.</p>

<p><strong>1990: Archie - The First Step</strong></p>

<p>In 1990, Archie became the first search engine, indexing filenames from FTP sites. Although rudimentary by today’s standards, Archie introduced the concept of indexing digital content, making it searchable. This marked the very beginning of our journey towards organizing the vast amount of information on the internet.</p>

<p><strong>1991-1992: Gopher and Veronica - Organizing Content</strong></p>

<p>The early ’90s brought Gopher, a protocol for organizing documents, and Veronica, a search tool for Gopher’s content. Together, they advanced the idea of searchable, organized web content, giving users more structure as they navigated the expanding web. It was the beginning of a more user-friendly approach to finding information.</p>

<p><strong>1995: Altavista - Speed and Power</strong></p>

<p>In 1995, Altavista set new standards for speed and search capabilities. It offered advanced search options and multilingual support, making it one of the first engines that truly focused on delivering fast and accurate results. Altavista was revolutionary, shaping the expectations of what a search engine could be.</p>

<p><strong>1996: Ask Jeeves - Natural Language Queries</strong></p>

<p>Ask Jeeves, launched in 1996, took a different approach by allowing users to input queries in natural language. It emphasized ease of use and intuitive question-answer interactions. Ask Jeeves introduced the idea that search engines should feel conversational and accessible, paving the way for the user-friendly interfaces we now take for granted.</p>

<p><strong>1998: Google - The Game Changer</strong></p>

<p>In 1998, Google changed everything. With its PageRank algorithm, which prioritized pages based on backlinks, Google transformed how we think about search relevance. The clean, minimalistic interface was a stark contrast to other search engines, and it quickly became the most popular choice for users. Google’s focus on delivering the most relevant results set a new benchmark for the industry.</p>

<p><strong>2004: Yahoo Search - Attempting to Compete</strong></p>

<p>By 2004, Yahoo had developed its own search engine after initially using Google for results. While Yahoo made attempts to compete with Google, it struggled to maintain user preference. Despite its efforts, Yahoo could not keep up with Google’s rapid growth and influence.</p>

<p><strong>2009: Bing - User-Centric Features</strong></p>

<p>Microsoft’s Bing, launched in 2009, offered a fresh perspective on search. Bing integrated features like cashback for shopping, visual search, and strong image integration, creating a more engaging user experience. It managed to carve out its own niche, focusing on visual appeal and user-centric functionalities.</p>

<p><strong>2024: OpenAI Search (ChatGPT) - The AI Revolution</strong></p>

<p>The latest milestone in search evolution is OpenAI Search, integrated with ChatGPT. Launched in 2024, this AI-driven search engine represents a significant shift towards real-time web search, conversational interaction, and source attribution. Unlike traditional search engines, OpenAI Search offers context-aware answers and an interactive, conversational experience. It’s not just about providing links anymore; it’s about understanding the intent behind a query and delivering a seamless, personalized information journey.</p>

<p><strong>The Future of Search: An Interactive Experience</strong></p>

<p>From Archie’s simple indexing to OpenAI Search’s sophisticated, conversational AI, search engines have continually evolved to better meet our needs. to better meet our needs. Today, with OpenAI Search, the user experience is no longer static; it’s an interactive, AI-driven journey that understands context and provides real-time insights. As we look ahead, it’s exciting to imagine where search will go next—continuing to transform, adapt, and redefine how we access information.</p>

<p><strong>Let’s Stay Connected</strong></p>

<ul>
  <li><a href="https://www.youtube.com/@dougfinke">YouTube Channel</a></li>
  <li><a href="https://x.com/dfinke">Twitter</a></li>
  <li><a href="https://www.linkedin.com/in/douglasfinke/">LinkedIn</a></li>
</ul>]]></content><author><name></name></author><category term="Search Engines" /><category term="Archie" /><category term="OpenAI" /><category term="Search Engines" /><category term="Archie" /><category term="OpenA" /><summary type="html"><![CDATA[The story of search engines is a journey of constant innovation and transformation. Let's explore the evolution from Archie to OpenAI Search.]]></summary></entry><entry><title type="html">Analyzing Monthly Changes A PowerShell Approach to Data Visualization</title><link href="https://dfinke.github.io/powershell/data%20visualization/excel%20automation/2024/10/24/Analyzing-Changes-A-PowerShell-Approach-to-using-Excel-for-Data-Visualization.html" rel="alternate" type="text/html" title="Analyzing Monthly Changes A PowerShell Approach to Data Visualization" /><published>2024-10-24T07:00:00+00:00</published><updated>2024-10-24T07:00:00+00:00</updated><id>https://dfinke.github.io/powershell/data%20visualization/excel%20automation/2024/10/24/Analyzing-Changes-A-PowerShell-Approach-to-using-Excel-for-Data-Visualization</id><content type="html" xml:base="https://dfinke.github.io/powershell/data%20visualization/excel%20automation/2024/10/24/Analyzing-Changes-A-PowerShell-Approach-to-using-Excel-for-Data-Visualization.html"><![CDATA[<p><img src="/images/posts/Analyzing-Monthly-Changes-A-PowerShell-Approach-to-Data Visualization.png" alt="alt text" /></p>

<h2 id="analyzing-changes-a-powershell-approach-using-excel-for-data-visualization">Analyzing Changes: A PowerShell Approach using Excel for Data Visualization</h2>

<ul>
  <li>
    <p><strong>Overview:</strong> In today’s data-driven environment, analyzing and visualizing data changes over time is critical for informed decision-making. This article explores a concise PowerShell script designed to process monthly data and output it into an Excel file, enhancing our ability to interpret changes effectively.</p>
  </li>
  <li>
    <p><strong>Importance:</strong> With organizations increasingly reliant on data for strategic insights, the ability to quickly visualize performance metrics has never been more essential. PowerShell offers a robust platform for automating data manipulation tasks, enabling analysts to focus on interpretation rather than routine processing.</p>
  </li>
</ul>

<h3 id="understanding-the-monthly-data">Understanding the Monthly Data</h3>

<ul>
  <li>
    <p><strong>Data Input:</strong> The PowerShell script begins by defining monthly data changes between two consecutive years (2023 and 2024). Each month has associated values representing performance, allowing users to observe trends and shifts in metrics.</p>
  </li>
  <li>
    <p><strong>Data Structure:</strong> The code utilizes a simple CSV format read directly into a PowerShell object, making it easy to manipulate and export to other formats.</p>
  </li>
  <li>
    <p><strong>Comparative Analysis:</strong> Change percentages are calculated for each month using the provided values, facilitating a quick assessment of whether performance is trending up or down year-over-year.</p>
  </li>
</ul>

<h3 id="exporting-data-to-excel">Exporting Data to Excel</h3>

<ul>
  <li>
    <p><strong>Excel File Creation:</strong> The script initializes an Excel file, ensuring any existing file is removed beforehand. This is crucial for maintaining up-to-date reports without manual intervention.</p>
  </li>
  <li>
    <p><strong>Data Exporting:</strong> By leveraging the <code class="language-plaintext highlighter-rouge">Export-Excel</code> cmdlet, the script seamlessly transfers the monthly data into an Excel worksheet, formatted for clarity and ease of use.</p>
  </li>
  <li>
    <p><strong>Formatting for Readability:</strong> The script applies formatting rules to enhance the presentation of data, such as bold text and background colors, thus improving user engagement with the Excel output.</p>
  </li>
</ul>

<h3 id="enhancing-output-with-formatting">Enhancing Output with Formatting</h3>

<ul>
  <li>
    <p><strong>Color-Coded Changes:</strong> The script employs customized cell formatting to signify increases and decreases in performance visibly. Positive changes are indicated with green, while negative changes appear in red, allowing for at-a-glance assessments of trends.</p>
  </li>
  <li>
    <p><strong>Number Formatting:</strong> Utilization of custom number formats within Excel allows for easy interpretation of percentage changes, making it straightforward to discern significant fluctuations.</p>
  </li>
  <li>
    <p><strong>Final Touches:</strong> The script automatically sizes columns and opens the Excel package for immediate review, maximizing user convenience and operational efficiency.</p>
  </li>
</ul>

<h3 id="code-explanation">Code Explanation</h3>

<p>The provided PowerShell script efficiently processes and visualizes monthly performance data in Excel, demonstrating key functionalities and strategies for automation:</p>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ConvertFrom-Csv</span><span class="w"> </span><span class="sh">@"
Month,2023YR,2024YR,Change
Jan,1000,1100,0.10
Feb,1200,1150,-0.0417
Mar,1500,1600,0.0667
Apr,1300,1250,-0.0385
May,1400,1500,0.0714
Jun,1600,1700,0.0625
Jul,1700,1650,-0.0294
Aug,1800,1800,0
Sep,2000,1950,-0.0250
Oct,2100,2200,0.0476
Nov,2200,2200,0
Dec,2300,2400,0.0435
"@</span><span class="w">
</span></code></pre></div></div>
<ul>
  <li><strong>Data Import:</strong> The script uses <code class="language-plaintext highlighter-rouge">ConvertFrom-Csv</code> to read the given inline CSV data, which represents monthly performance metrics over two distinct years.</li>
</ul>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$xlfile</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"</span><span class="bp">$PSScriptRoot</span><span class="s2">\spike.xlsx"</span><span class="w">
</span><span class="n">Remove-Item</span><span class="w"> </span><span class="nv">$xlfile</span><span class="w"> </span><span class="nt">-ErrorAction</span><span class="w"> </span><span class="nx">SilentlyContinue</span><span class="w">
</span></code></pre></div></div>
<ul>
  <li><strong>File Management:</strong> It specifies the Excel file location and ensures that any previous versions are deleted, preventing potential errors during export.</li>
</ul>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$xlPkg</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$data</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">Export-Excel</span><span class="w"> </span><span class="nt">-Path</span><span class="w"> </span><span class="nv">$xlfile</span><span class="w"> </span><span class="nt">-AutoSize</span><span class="w"> </span><span class="nt">-PassThru</span><span class="w"> </span><span class="nt">-StartRow</span><span class="w"> </span><span class="nx">3</span><span class="w"> </span><span class="nt">-StartColumn</span><span class="w"> </span><span class="nx">4</span><span class="w">
</span></code></pre></div></div>
<ul>
  <li><strong>Exporting Data:</strong> The <code class="language-plaintext highlighter-rouge">Export-Excel</code> cmdlet takes the data and formats it into an Excel sheet, managing layout parameters such as row and column starts.</li>
</ul>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Set-ExcelRange</span><span class="w"> </span><span class="nt">-Worksheet</span><span class="w"> </span><span class="nv">$xlPkg</span><span class="o">.</span><span class="nf">Sheet1</span><span class="w"> </span><span class="nt">-Range</span><span class="w"> </span><span class="s2">"D3:G3"</span><span class="w"> </span><span class="nt">-Bold</span><span class="w"> </span><span class="nt">-BackgroundColor</span><span class="w"> </span><span class="nx">LightGreen</span><span class="w"> </span><span class="nt">-HorizontalAlignment</span><span class="w"> </span><span class="nx">Center</span><span class="w">
</span><span class="n">Set-ExcelRange</span><span class="w"> </span><span class="nt">-Worksheet</span><span class="w"> </span><span class="nv">$xlPkg</span><span class="o">.</span><span class="nf">Sheet1</span><span class="w"> </span><span class="nt">-Range</span><span class="w"> </span><span class="s2">"D4:D15"</span><span class="w"> </span><span class="nt">-Bold</span><span class="w"> </span><span class="nt">-BackgroundColor</span><span class="w"> </span><span class="nx">LightBlue</span><span class="w"> </span><span class="nt">-HorizontalAlignment</span><span class="w"> </span><span class="nx">Center</span><span class="w">
</span></code></pre></div></div>
<ul>
  <li><strong>Cell Formatting:</strong> Subsequent lines format specific ranges, enhancing readability with color cues and centralized text.</li>
</ul>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Set-ExcelRange</span><span class="w"> </span><span class="nt">-Worksheet</span><span class="w"> </span><span class="nv">$xlPkg</span><span class="o">.</span><span class="nf">Sheet1</span><span class="w"> </span><span class="nt">-Range</span><span class="w"> </span><span class="s2">"G3:G15"</span><span class="w"> </span><span class="nt">-NumberFormat</span><span class="w"> </span><span class="s2">"[color10]0.0#%▲;[red]0.0#%▼;[blue]0.0#% ▬"</span><span class="w"> </span><span class="nt">-AutoSize</span><span class="w">
</span><span class="n">Close-ExcelPackage</span><span class="w"> </span><span class="nv">$xlPkg</span><span class="w"> </span><span class="nt">-Show</span><span class="w">
</span></code></pre></div></div>
<ul>
  <li><strong>Final Adjustments:</strong> The final adjustments set the number format for percentage changes, ensuring that visual cues clearly indicate trends before opening the file for review.</li>
</ul>

<h2 id="check-out-the-video-tutorial">Check Out the Video Tutorial</h2>

<p>From Raw Data to Insights: PowerShell-Driven Excel Magic. Watch the video below to see the script in action and learn how to visualize monthly changes effectively.</p>

<center><a href="https://youtu.be/jUzYlmbOS9o"><img src="https://img.youtube.com/vi/jUzYlmbOS9o/0.jpg" width="350" /></a></center>

<h2 id="conclusion">Conclusion</h2>

<ul>
  <li>
    <p><strong>Summary:</strong> The article showcases a PowerShell script that not only processes and exports monthly data into a formatted Excel file but also highlights how quick visualization can significantly aid in data analysis.</p>
  </li>
  <li>
    <p><strong>Implications:</strong> Such automation tools empower data analysts to make more informed decisions swiftly, as accessibility to visual data trends can improve responsiveness to market changes.</p>
  </li>
</ul>]]></content><author><name></name></author><category term="PowerShell" /><category term="Data Visualization" /><category term="Excel Automation" /><category term="PowerShell" /><category term="Excel" /><category term="Data Analysis" /><summary type="html"><![CDATA[This article explores how PowerShell can be used to visualize monthly data changes through Excel, emphasizing its applications in data analysis.]]></summary></entry><entry><title type="html">Harnessing PowerShell with OpenAI: An In-Depth Look at Audio Integration</title><link href="https://dfinke.github.io/technology/2024/10/18/Harnessing-PowerShell-with-OpenAI-An-In-Depth-Look-at-Audio-Integration.html" rel="alternate" type="text/html" title="Harnessing PowerShell with OpenAI: An In-Depth Look at Audio Integration" /><published>2024-10-18T14:33:21+00:00</published><updated>2024-10-18T14:33:21+00:00</updated><id>https://dfinke.github.io/technology/2024/10/18/Harnessing-PowerShell-with-OpenAI-An-In-Depth-Look-at-Audio-Integration</id><content type="html" xml:base="https://dfinke.github.io/technology/2024/10/18/Harnessing-PowerShell-with-OpenAI-An-In-Depth-Look-at-Audio-Integration.html"><![CDATA[<p><img src="/images/posts/Harnessing-Audio-Integration.png" alt="alt text" /></p>

<h2 id="harnessing-powershell-with-openai-an-in-depth-look-at-audio-integration">Harnessing PowerShell with OpenAI: An In-Depth Look at Audio Integration</h2>

<ul>
  <li>
    <p><strong>Overview:</strong> In an age where artificial intelligence transforms various domains, integrating AI functionalities into scripting languages opens new avenues for automation. One interesting use case involves using PowerShell to convert text into audio by leveraging OpenAI’s API. This article delves deep into the underlying code, its functionality, and its implications in the tech landscape.</p>
  </li>
  <li>
    <p><strong>Importance:</strong> As OpenAI’s text-to-speech capabilities become increasingly robust and accessible, the ability to implement these features via PowerShell presents a powerful tool for developers and businesses alike. This capability allows for automation in creating audio content, enhancing accessibility, and providing innovative user experiences.</p>
  </li>
</ul>

<h3 id="understanding-the-code">Understanding the Code</h3>

<p>The following PowerShell script illustrates how to utilize OpenAI’s API to convert text into speech:</p>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$prompt</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"Recite first few lines of the Gettysburg Address"</span><span class="w"> 

</span><span class="nv">$headers</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">@{</span><span class="s2">"Content-Type"</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"application/json"</span><span class="p">;</span><span class="w"> </span><span class="s2">"Authorization"</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"Bearer </span><span class="si">$(</span><span class="nv">$</span><span class="nn">env</span><span class="p">:</span><span class="nv">OpenAIKey</span><span class="si">)</span><span class="s2">"</span><span class="w"> </span><span class="p">}</span><span class="w">

</span><span class="nv">$body</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="n">ordered</span><span class="p">]@{</span><span class="w">
    </span><span class="nx">model</span><span class="w">      </span><span class="o">=</span><span class="w"> </span><span class="s2">"gpt-4o-audio-preview"</span><span class="w">
    </span><span class="nx">modalities</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">@(</span><span class="s2">"text"</span><span class="p">,</span><span class="w"> </span><span class="s2">"audio"</span><span class="p">)</span><span class="w">
    </span><span class="nx">audio</span><span class="w">      </span><span class="o">=</span><span class="w"> </span><span class="p">@{</span><span class="w"> </span><span class="nx">voice</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"nova"</span><span class="p">;</span><span class="w"> </span><span class="nx">format</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"wav"</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="c"># alloy, echo, fable, onyx, nova, shimmer</span><span class="w">
    </span><span class="nx">messages</span><span class="w">   </span><span class="o">=</span><span class="w"> </span><span class="p">@(@{</span><span class="w"> </span><span class="nx">role</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"user"</span><span class="p">;</span><span class="w"> </span><span class="nx">content</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$prompt</span><span class="w"> </span><span class="p">})</span><span class="w">
</span><span class="p">}</span><span class="w">

</span><span class="nv">$params</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">@{</span><span class="w">
    </span><span class="nx">Uri</span><span class="w">     </span><span class="o">=</span><span class="w"> </span><span class="s2">"https://api.openai.com/v1/chat/completions"</span><span class="w">
    </span><span class="nx">Method</span><span class="w">  </span><span class="o">=</span><span class="w"> </span><span class="s2">"Post"</span><span class="w">
    </span><span class="nx">Headers</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$headers</span><span class="w">
    </span><span class="nx">Body</span><span class="w">    </span><span class="o">=</span><span class="w"> </span><span class="err">(</span><span class="nv">$body</span><span class="w"> </span><span class="err">|</span><span class="w"> </span><span class="nx">ConvertTo</span><span class="err">-</span><span class="nx">Json</span><span class="err">)</span><span class="w">
</span><span class="p">}</span><span class="w">

</span><span class="nv">$result</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Invoke-RestMethod</span><span class="w"> </span><span class="err">@</span><span class="nx">params</span><span class="w">

</span><span class="nv">$wavDataBytes</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="n">Convert</span><span class="p">]::</span><span class="n">FromBase64String</span><span class="p">(</span><span class="nv">$result</span><span class="o">.</span><span class="n">choices</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="nf">message</span><span class="o">.</span><span class="nf">audio</span><span class="o">.</span><span class="nf">data</span><span class="w"> </span><span class="p">)</span><span class="w">
</span><span class="nv">$wavPath</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"</span><span class="bp">$PSScriptRoot</span><span class="s2">\output.wav"</span><span class="w">

</span><span class="p">[</span><span class="n">System.IO.File</span><span class="p">]::</span><span class="n">WriteAllBytes</span><span class="p">(</span><span class="nv">$wavPath</span><span class="p">,</span><span class="w"> </span><span class="nv">$wavDataBytes</span><span class="p">)</span><span class="w">

</span><span class="n">Invoke-Item</span><span class="w"> </span><span class="nv">$wavPath</span><span class="w">
</span></code></pre></div></div>

<ul>
  <li>The script begins by defining a prompt, asking OpenAI to recite the first few lines of the Gettysburg Address.</li>
  <li>Headers are established to communicate with the API, including content type and authorization using an API key stored in the environment.</li>
  <li>The body of the request is carefully structured to specify the model, modalities (text and audio), the voice to be used, and the conversation context.</li>
</ul>

<h3 id="script-workflow">Script Workflow</h3>

<ul>
  <li>The API endpoint is defined, and a POST request is launched using the <code class="language-plaintext highlighter-rouge">Invoke-RestMethod</code> cmdlet. This command sends the structured request to OpenAI’s server.</li>
  <li>The result from the API call is captured, extracting the audio data from the response.</li>
  <li>Finally, the audio data is decoded from its base64 format and saved as a WAV file on the local machine. The output file is then automatically opened for playback.</li>
</ul>

<h3 id="benefits-of-powershell-with-openai">Benefits of PowerShell with OpenAI</h3>

<ul>
  <li><strong>Accessibility:</strong> By employing PowerShell, a common tool for system administrators, AI features become more accessible without the need for extensive programming knowledge.</li>
  <li><strong>Automation:</strong> Organizations can automate content creation, enabling diverse applications like generating audiobooks, announcements, and accessibility tools for visually impaired users.</li>
  <li><strong>Cross-Platform Use:</strong> PowerShell’s compatibility with various environments means developers can implement OpenAI features seamlessly, enhancing their existing workflows.</li>
</ul>

<h3 id="code-explanation">Code Explanation</h3>

<p>The provided script exemplifies a practical blend of PowerShell’s functionality with OpenAI’s capabilities. It demonstrates the basics of composing a structured API request, proper handling of JSON data, and the manipulation of binary audio data directly from a response. Each component of the script is modular, allowing users to adapt the prompt and configuration settings for different outputs or projects.</p>

<h2 id="conclusion">Conclusion</h2>
<ul>
  <li><strong>Summary:</strong> This exploration of PowerShell’s integration with the OpenAI API emphasizes the simplicity and potential of automating audio content generation. The provided code serves as a foundational example that can be expanded or modified for various applications.</li>
  <li><strong>Implications:</strong> As AI technologies continue to evolve, combining them with traditional scripting languages like PowerShell will enable greater innovations in content delivery, user engagement, and automation. This trend is likely to shape how organizations approach audio content creation in the future.</li>
</ul>

<h2 id="references">References</h2>
<ul>
  <li><a href="https://github.com/dfinke/PSAI">PowerShell module for OpenAI API. PSAI - GitHub</a></li>
  <li><a href="https://platform.openai.com/docs/guides/audio/audio-generation">OpenAI Audio Generation</a></li>
</ul>]]></content><author><name></name></author><category term="Technology" /><category term="PowerShell" /><category term="OpenAI" /><category term="AI" /><category term="Programming" /><summary type="html"><![CDATA[Exploring how to leverage OpenAI's API for text-to-audio conversion using PowerShell, including code breakdown and practical applications.]]></summary></entry></feed>