Jekyll2019-02-25T20:27:27+00:00https://mkellerman.github.io/feed.xmlPS /mkellerman&gt;little piece of the web to dump my own experiences using powershellMarc R KellermanIntroducing PSTwitterAPI - a PowerShell module for the Twitter API2019-01-25T00:00:00+00:002019-01-25T00:00:00+00:00https://mkellerman.github.io/Introducing_PSTwitterAPI<h2 id="introducing-pstwitterapi">Introducing PSTwitterAPI</h2> <p><code class="highlighter-rouge">&lt;salespitch&gt;</code>Ever wanted to get twitter notifications on your build jobs? Or collect some tweets for a report? Or automate some tweets for your blog post? All in PowerShell? This is the module for you! <code class="highlighter-rouge">&lt;/salespitch&gt;</code></p> <p>Seriously, for whatever the reasons you need to interact with the Twitter&#8217;s API, this is the most complete solution available out there!</p> <h2 id="twitter-api-helper-functions">Twitter API Helper functions</h2> <p>I originally created the module <a href="https://github.com/mkellerman/invoketwitterapis">InvokeTwitterAPIs</a> that is sitting in the <a href="https://www.powershellgallery.com/packages/InvokeTwitterAPIs/2.5">PowerShell Gallery</a>, but a lot has changed since then. I wanted to refactor the whole project and make it easier/faster overall. It wasn&#8217;t complete, and many endpoints where missing.</p> <p>Instead of writing each endpoint by hand, I created a Script to scrape the Twitter API documentation, get the resource URL, description and parameters. It then uses this to generate all the helper functions dynamically. You can go check it out here: <a href="https://github.com/mkellerman/PSTwitterAPI/tree/master/APIHelper">GitHub: APIHelper</a></p> <p>It&#8217;s not pretty, but it does the job!</p> <h2 id="example-1-get-twitter-user-information">Example 1: Get Twitter user information</h2> <div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Import-Module PSTwitterAPI <span class="c1"># Provide Authentication for the Twitter API</span> <span class="c1"># https://twittercommunity.com/t/how-to-get-my-api-key/7033</span> <span class="nb">Set</span>-TwitterOAuthSettings -ApiKey <span class="nv">$env</span>:ApiKey -ApiSecret <span class="nv">$env</span>:ApiSecret -AccessToken <span class="nv">$env</span>:AccessToken -AccessTokenSecret <span class="nv">$env</span>:AccessTokenSecret <span class="c1"># Get user twitter profile</span> Get-TwitterUsers_Lookup -screen_name <span class="s1">'mkellerman'</span> </code></pre></div></div> <ol> <li>Provide authentication token to the module</li> <li>Use one of the +120 helper functions to get/send requests to Twitter</li> <li>Profit</li> </ol> <h2 id="example-2-create-wordcloud-from-your-recent-tweets">Example 2: Create WordCloud from your recent tweets</h2> <div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Import-Module PSTwitterAPI Import-Module PSWordCloud <span class="nb">Set</span>-TwitterOAuthSettings -ApiKey <span class="nv">$env</span>:ApiKey -ApiSecret <span class="nv">$env</span>:ApiSecret -AccessToken <span class="nv">$env</span>:AccessToken -AccessTokenSecret <span class="nv">$env</span>:AccessTokenSecret <span class="c1"># Request the last 200 tweets from the desired user.</span> <span class="nv">$TwitterStatuses</span> <span class="o">=</span> Get-TwitterStatuses_UserTimeline -screen_name <span class="s1">'mkellerman'</span> -count 200 <span class="c1"># Get list of stop words that should be excluded from the world cloud.</span> <span class="nv">$ExcludeWord</span> <span class="o">=</span> <span class="o">(</span><span class="nb">Invoke-WebRequest</span> -Uri <span class="s1">'https://raw.githubusercontent.com/Alir3z4/stop-words/master/english.txt'</span> -UseBasicParsing<span class="o">)</span>.Content -Split <span class="s2">"</span><span class="se">`n</span><span class="s2">"</span> <span class="c1"># Generate a word cloud from the text in your tweets.</span> New-WordCloud -InputObject <span class="nv">$TwitterStatuses</span>.text -Path <span class="s2">".\TwitterStatuses.png"</span> -ExcludeWord <span class="nv">$ExcludeWord</span> -ImageSize 720p </code></pre></div></div> <ol> <li>Provide authentication token to the module</li> <li>Get last 200 tweets from your user</li> <li>Get stop words to be excluded from the world cloud</li> <li>Generate word cloud</li> <li>Profit</li> </ol> <figure class=""> <img src="/assets/posts/2020-01-25-Introducing_PSTwitterAPI_WordCloud.png" alt="PSWordCloud for @mkellerman using PSTwitterAPI" /> <figcaption>PSWordCloud for @mkellerman using PSTwitterAPI </figcaption> </figure> <h2 id="open-source-come-and-help">Open Source: Come and help!</h2> <p>I&#8217;ve built the foundation, but there are many things left to do:</p> <ul> <li>Test each helper function (Manual/Pester).</li> <li>If you see a missing API endpoint, create an Issue.</li> <li>Any improvements you can suggest/make <strong>please</strong> make a PR!</li> </ul> <p>You are using Twitter via Powershell? Join me on the PowerShell <a href="http://powershell.slack.com">Slack</a>/<a href="https://discord.gg/HjV8R5">Discord</a> #PSTwitterAPI channel!</p> <p>And as always, go check it out and let me know what you think!</p>Marc R Kellermanthe most complete solution available out there!Copy-xItem to Remote Session2019-01-02T00:00:00+00:002019-01-02T00:00:00+00:00https://mkellerman.github.io/Copy-xItem_to_remote_session<h3 id="copying-a-filefunctionmodule-to-a-powershell-remote-session">Copying a file/function/module to a Powershell Remote Session</h3> <p>Most of the time I write my script locally. I then add a second layer to run it remotely, and make sure everything works well. Building my scripts like a cake.</p> <p>I&#8217;ve build a few tools to help me copy files, functions and modules over to a remote machine. I didn&#8217;t want to go the UNC share to copy files over the conventional way.. because &lt;insert valid, but pointless reason here&gt;.</p> <p>In PS 5.1, Copy-Item got a new property: -ToSession. I thought that was brilliant! I wish more Cmdlets had this property. I then decided to implement my own version of this, so i can use it in older environments.</p> <h4 id="copy-xitem">Copy-xItem</h4> <div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Import-Module Copy-xItem $Session = New-PSSession -ComputerName $ComputerName -Credential $Credential Copy-xItem -Session $Session -Path 'C:\Workspace' -Destination 'C:\Workspace' -Recurse -Force Invoke-Command -Session $Session -ScriptBlock { Get-ChildItem 'C:\Workspace' } </code></pre></div></div> <h4 id="copy-xfunction">Copy-xFunction</h4> <div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Import-Module Copy-xItem Import-Module .\Get-PendingReboot.ps1 $Session = New-PSSession -ComputerName $ComputerName -Credential $Credential Copy-xFunction -Session $Session -Name 'Get-PendingReboot' Invoke-Command -Session $Session -ScriptBlock { Get-PendingReboot } </code></pre></div></div> <h4 id="copy-xmodule">Copy-xModule</h4> <div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Import-Module Copy-xItem Import-Module .\Get-PendingReboot.ps1 $Session = New-PSSession -ComputerName $ComputerName -Credential $Credential Copy-xModule -Session $Session -Name 'Get-PendingReboot' Invoke-Command -Session $Session -ScriptBlock { Get-PendingReboot } </code></pre></div></div> <h3 id="conclusion">Conclusion</h3> <p>So there you have it.. little duck tape, a couple paperclips, and presto, my own little script to copy over files, functions and modules to a remote PowerShell Session.</p> <p>You really need to see the source to appreciate it. I&#8217;ll dump the source of Copy-xItem, Copy-xFunction and Copy-xModule, on GitHub.</p> <p>https://github.com/mkellerman/Copy-xItem</p> <p>Go check it out and let me know what you think! And dont be shy to make PRs!</p>Marc R KellermanNeed to copy files, functions and modules to a remote session using older versions of Powershell?Import functions in remote sessions2018-07-29T00:00:00+00:002018-07-29T00:00:00+00:00https://mkellerman.github.io/Import_custom_functions_into_your_backgroundjob<p>Want to use a custom function inside a PSSession or BackgroundJob, use this one-liner to do all the heavy lifting.</p> <div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Invoke-Expression ${Using:Function:&lt;functionname&gt;}.Ast.Extent.Text </code></pre></div></div> <p>Here&#8217;s a simple example:</p> <div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>function Invoke-HelloWorld { Write-Warning "Hello World" } $ScriptBlock = { Invoke-Expression ${Using:Function:Invoke-HelloWorld}.Ast.Extent.Text Invoke-HelloWorld } Start-Job -ScriptBlock $ScriptBlock | Receive-Job -Wait -AutoRemoveJob </code></pre></div></div> <p>How does it work? Let&#8217;s break it down:</p> <div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>${} : Curly braces in PowerShell variable names allow for arbitrary characters in the name of the variable. $Using:&lt;VariableName&gt; : Using Local variables in remote session. $Function:&lt;FunctionName&gt; : Provides access to the functions defined in Windows PowerShell. </code></pre></div></div> <p>We are basically doing some kind of inception, pulling the function definition from our local session.</p> <p>But why <code class="highlighter-rouge">${}.Ast.Extent.Text</code>? my head hurts&#8230;</p> <p>We dont want the scriptblock inside the function. We want the entire function definition as a string.</p> <p>Hope this helps!</p> <p>And dont forget to msg me on Twitter (<a href="twitter.com/mkellerman">@mkellerman</a>), love getting your feedback!</p> <p>References:</p> <ul> <li> <p>About Remote Variables: <a href="https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_remote_variables?view=powershell-6">Link</a></p> </li> <li> <p>Function Provider: <a href="https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/providers/function-provider?view=powershell-6">Link</a></p> </li> </ul>Marc R Kellermanuse this one-liner to do all the heavy liftingStart-Job like a boss2018-07-16T00:00:00+00:002018-07-16T00:00:00+00:00https://mkellerman.github.io/Start-Job_like_a_boss<p>Ever wanted to Start Background Jobs (Start-Job) with some Throttle? Or with a Timeout? And how about loading your local user session functions inside your Background Job?</p> <p>I use Start-Job daily. Managing +300 VMs for our QA environment in VCenter (VMWare) and SCVMM (Hyper-V). It’s a breeze when you know how to do things in parallel. Many scripts/modules are out there to help you do it quickly and efficiently. Most of them, are built around Runspaces and for good reasons. Using Runspaces are blazing fast! But in some cases, using Runspaces isn’t the right option. For those times, I’ve built Invoke-Job.</p> <p>I wanted to replicate the Start-Job cmdlet, but add a few extra parameters:</p> <ul> <li>ImportFunctions</li> <li>Throttle</li> <li>Timeout</li> <li>PassThru</li> </ul> <p>Link: <a href="https://github.com/mkellerman/Invoke-Job">https://github.com/mkellerman/Invoke-Job</a></p> <h3 id="lets-make-a-simple-example">Let’s make a simple example:</h3> <div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Import-Module .\Invoke-Job.ps1 function Invoke-HelloWorld { Write-Warning 'Hello World' } (1..10) | Invoke-Job -ScriptBlock { Invoke-HelloWorld } -ImportFunctions -Throttle 3 -All </code></pre></div></div> <p>This example shows how to invoke a custom function, inside of the background job, without having to do anything to load that function. It does it all for me. the -All parameter will show be jobs when they are starting and when they are completed. If you remove that parameter, you’ll only see when they are done. As a DevOps, i like seeing things start/stop. ;)</p> <h3 id="now-that-we-get-the-basics-lets-bump-it-up-a-notch">Now that we get the basics, let’s bump it up a notch:</h3> <div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Import-Module .\Invoke-Job.ps1 # Load a script in this user session # https://gallery.technet.microsoft.com/scriptcenter/Get-PendingReboot-Query-bdb79542 Import-Module .\Get-PendingReboot.ps1 # Make a simple ScriptBlock that will receive the computername from the pipeline and execute the script against the remote computer. In this case, Get-PendingReboot that we've loaded in this current session. $ScriptBlock = { Process { # Collect the InputObject sent through the Pipeline. $ComputerName = $_ Try { # Because Get-PendingReboot has been imported into this session, I can call the function directly. # I'm also $Using variables from the parent session. Everything works as expected. Invoke-Command -ComputerName $ComputerName -Credential $Using:Credential -ScriptBlock ${function:Get-PendingReboot} } Catch { Write-Error $_.Exception.Message } } } # Get list of computers and set the credential used for the remote execution. $Computers = Get-Content -Path '.\computers.txt' $Credential = Get-Credential # Start-Job 4 jobs at a time, with a timeout of 30 seconds, and return the results (not the Job object). And beautify it by presenting the results in a table. $Computers | Invoke-Job -ScriptBlock $ScriptBlock -Throttle 4 -Timeout 30 -ImportFunctions -PassThru | Format-Table </code></pre></div></div> <p>This example shows how to execute a function against many computers, but with a throttle and a timeout. And output the results directly.</p> <p>And here you go. Simple and easy to read code. If I had to put the code here to handle the Throttle, the Timeout, ImportFunctions and the PassThru, it would have been +250 lines of code and hard for someone else to read and maintain.</p> <p>Let me know what you guys think!</p> <p>Msg me on Twitter, love getting your feedback!</p> <p>Link: <a href="https://github.com/mkellerman/Invoke-Job">https://github.com/mkellerman/Invoke-Job</a></p>Marc R KellermanEver wanted to Start-Job with Throttle?Death to PsExec2018-04-12T00:00:00+00:002018-04-12T00:00:00+00:00https://mkellerman.github.io/Death_to_psexec<p>As a first technical blog post, I’ve decide to document some of the work I did to move away from <a href="https://docs.microsoft.com/en-us/sysinternals/downloads/psexec">PsExec</a> in our environment.</p> <h4 id="but-why-whats-wrong-with-psexec">But why… What’s wrong with PsExec?</h4> <p>Currently we use PsExec to remotely execute our NUnit tests against our test environment. It works most of the time, but when there is any network interruption or connectivity issue, the session drops, but the actual process continues on the remote machine. You then have to implement tons of error handling to re-connect and try to continue where you left off, or pick up the test results… it’s simply a nightmare.</p> <h4 id="why-not-use-powershell-remote-sessions">Why not use PowerShell Remote Sessions?</h4> <p>Have you heard of the Double-Hop issue? Ashley McGlone (@GoateePFE) has a great <a href="https://blogs.technet.microsoft.com/ashleymcglone/2016/08/30/powershell-remoting-kerberos-double-hop-solved-securely/">article</a> explaining the issue and offering tons of solutions.</p> <h4 id="so-why-not-implement-one-of-those-solutions">So why not implement one of those solutions?</h4> <p>Simple: I wanted to point my script to an IPAddress, and magically have it ‘work’. I didn’t want to have to setup an AD environment, or configure anything on the remote box.</p> <h4 id="marc-youre-too-damn-difficult">Marc… You’re too damn difficult.</h4> <p>I want a simple implementation that replicated the <code class="highlighter-rouge">Invoke-Command</code> cmdlet, but add a <code class="highlighter-rouge">-As $Credential</code> to provide the &lt;PSCredential&gt; I want that &lt;ScriptBlock&gt; to run on the remote machine. But have the connectivity benefits of the Powershell Remoting Session.</p> <h4 id="what-i-want-it-to-look-like">What I want it to look like:</h4> <div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Invoke-CommandAs -Session &lt;Session&gt; -ScriptBlock &lt;ScriptBlock&gt; -As &lt;PSCredential&gt; </code></pre></div></div> <p>First step, establish a Powershell Remote Session to the remote machine, and execute a process with a different set of credential… and return a powershell object? ¯\<em>(ツ)</em>/¯</p> <p>Should be simple enough…</p> <h4 id="executing-a-process-with-a-different-set-of-credentials-easy-peasy-lemon-squeezy">Executing a process with a different set of credentials? Easy peasy lemon squeezy…</h4> <!-- ```` # Using Start-Process Start-Process -FilePath 'powershell.exe' -ArgumentList '-Command Get-Process' -Credential $Credential ```` ```` # Using Invoke-WmiMethod Invoke-WmiMethod -Class Win32_Process -Name Create -ArgumentList 'powershell.exe -Command Get-Process' -Credential $Credential ```` ```` # Using System.Diagnostics.Process [System.Diagnostics.Process]::Start( "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe", "-Command Get-Process", $Credential.UserName.Split('\')[1] , $Credential.Password , $Credential.UserName.Split('\')[0] ) ```` --> <p>I wanted to try out an replicated the <code class="highlighter-rouge">RunAs.exe</code> command, to start my powershell.exe process under another set of credentials. But I wasn’t able to launch it remotely and provide the credentials to the console.</p> <h4 id="invoke-cmdas">Invoke-CmdAs</h4> <p>A colleague of mine found a <a href="https://github.com/JetBrains/runAs">Jetbrains/runAs</a> project that replicates the RunAs.exe utility, but allows the credentials to be passed in the command line. View my wrapper here: <a href="https://github.com/mkellerman/PSRunAs/blob/master/Invoke-CmdAs/Invoke-ExpressionAs.ps1">Invoke-ExpressionAs</a></p> <p>But having binaries being copied over is definitely not elegant.</p> <h4 id="invoke-runas">Invoke-RunAs</h4> <p>I then found <b>Invoke-RunAs</b> by Ruben Boonen (@FuzzySec) that uses Add-Type to load the DLL and invoke ‘Advapi32::CreateProcessWithLogonW’ the same way <code class="highlighter-rouge">RunAs.exe</code> is doing. View my wrapper here: <a href="https://github.com/mkellerman/PSRunAs/blob/master/Invoke-RunAs">Invoke-RunAs</a></p> <h4 id="start-processasuser">Start-ProcessAsUser</h4> <p>Also, verify similarly, <b>Start-ProcessAsUser</b> by Matthew Graeber (@mattifestation) with modifications by Lee Christensen (@tifkin_) uses Reflection to load the DLL and invoke ‘Advapi32::CreateProcessWithLogonW’ the same way RunAs.exe is doing. View my wrapper here: <a href="https://github.com/mkellerman/PSRunAs/blob/master/Start-ProcessAsUser">Start-ProcessAsUser</a></p> <p>All these implementations required some code wizardry to return a PowerShell Objects.</p> <h4 id="invoke-scheduledtask">Invoke-ScheduledTask</h4> <p>Alternatively, one solution that is very often talked about is to create a Scheduled Task on the remote machine, and let ‘SYSTEM’ (or any supplied credential) execute your process. It’s simple, and after some digging around, i found out it creates a ScheduledJob, and you can Receive-Job the result as a Powershell Object.</p> <p>So i created a <code class="highlighter-rouge">Invoke-ScheduleTask</code> cmdlet to help simplify this and created a wrapper to copy the implementations above. View my wrapper here: <a href="https://github.com/mkellerman/PSRunAs/blob/master/Invoke-ScheduledJob/">Invoke-ScheduledJob</a></p> <h3 id="simpler-is-better">Simpler is better</h3> <p>After playing around with all these solutions for a while, I’ve decided to implement the <code class="highlighter-rouge">Invoke-ScheduleJob</code> into my final solution, as it returns native PowerShell Objects, and doesn’t break any of the output streams.</p> <p>Go check it out here: <a href="https://github.com/mkellerman/Invoke-CommandAs">Invoke-CommandAs</a>.</p> <p>It’s also in the PowerShell Gallery!</p> <div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Install Module Install-Module -Name Invoke-CommandAs </code></pre></div></div> <div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Execute Locally. Invoke-CommandAs -ScriptBlock { Get-Process } # Execute As different Credentials. Invoke-CommandAs -ScriptBlock { Get-Process } -As $Credential # Execute Remotely using ComputerName/Credential. Invoke-CommandAs -ComputerName 'VM01' -Credential $Credential -ScriptBlock { Get-Process } # Execute Remotely using PSSession. Invoke-CommandAs -Session $PSSession -ScriptBlock { Get-Process } # Execute Remotely on multiple Computers at the same time. Invoke-CommandAs -ComputerName 'VM01', 'VM02' -Credential $Credential -ScriptBlock { Get-Process } # Execute Remotely as Job. Invoke-CommandAs -Session $PSSession -ScriptBlock { Get-Process } -AsJob </code></pre></div></div> <p>I’m sure there is tons of other ways to do this, or some scenarios that makes one solution better than others, and would love to hear about them!</p> <p>Msg me on Twitter!</p> <hr /> <p>Update:</p> <p>2018-04-12: Reddit user <a href="https://www.reddit.com/r/PowerShell/comments/8bvhcr/blog_death_to_psexec_how_to_invoke_powershell_as/dxa42tr/">kusuriya</a> pointed to <a href="https://github.com/clymb3r/PowerShell/blob/master/Invoke-TokenManipulation/Invoke-TokenManipulation.ps1">Invoke-TokenManipulation</a> to impersonate another users Logon Token.</p>Marc R KellermanPowerShell alternatives to PsExec...Look ma’, i’m a blogger!2018-04-11T00:00:00+00:002018-04-11T00:00:00+00:00https://mkellerman.github.io/Look_ma_im_a_blogger<p>I’m at the <a href="https://powershell.org/summit/">PSSummit 2018</a>, and everyone has a blog… so here I am!</p> <p>Note to future me: <b>What where you thinking?</b></p> <p>More notes to self: <b>Have your wife spell check all them things<b></b></b></p> <p>¯\<em>(ツ)</em>/¯</p>Marc R Kellermanthe peer pressure at these conferences...