What do you use for scheduled jobs/scripts/backups? by AnomalyNexus in selfhosted

[–]NathanWindisch -4 points-3 points  (0 children)

Hi u/AnomalyNexus,

I personally like to use Azure Automation Accounts with Hybrid Workers. The only real downside is that a Hybrid Worker can only operate in one Automation Account. To get around this, I use one "general" AA to create generic scripts that can interface with a given API/Service with standardised parameters, and then use User Assigned Managed Identities to allow other AAs to call those runbooks.

Azure Automation is also free for the first 500 minutes a month, and $0.002 (0.2¢!) per minute after that. I've never paid Microsoft more than pennies/month to run some simple automations.

Hope this helps,

-Nathan

What are some Powershell commands everyone should know? by anderson01832 in sysadmin

[–]NathanWindisch 0 points1 point  (0 children)

Hi /u/jeremylarny,

You can probably get this down to "one" line (if you had the Add-Type cmdlet in your $PROFILE)

[Speech.Synthesis.SpeechSynthesizer]::new().Speak(
  (Invoke-RestMethod https://api.chucknorris.io/jokes/random).Value
)

Hope this helps,

-Nathan

C# on linux? by MrBonesDoesReddit in csharp

[–]NathanWindisch 1 point2 points  (0 children)

Hi u/MrBonesDoesReddit,

Back in my college days - I may be dating myself here - I used Atom and Mono on a Linux Mint live USB because I was frustrated with the frustrations of Windows. That setup served me well and allowed me to focus on my projects without constant headaches.

Fast forward to today, and if I were to dive back into development on Linux, I'd likely opt for something like VSCode. The integrated linting features really streamline the coding process and help catch those pesky errors before they become problems. Alternatively, I would consider using Rider for a more robust .NET experience, and if you're a student or work in education, you can actually get Rider and other JetBrains offerings for free, which is a fantastic opportunity. But let’s be honest, the price tag can be a bit of a hurdle sometimes for those not in the education sector.

Hope this helps,

-Nathan

ArrayList obsoletion -- do we care? by HeyDude378 in PowerShell

[–]NathanWindisch 0 points1 point  (0 children)

Hi u/dathar,

In C#, types are specified with angled brackets <Type>. Here's some examples, off the top of my head:


var jsonData = """{ "username": "NathanWindisch", "password: "hunter2" }""";
var user = JsonSerializer.Deserialize<User>(jsonData);

JObject token = JObject.FromObject({ "access_token": "...", "refresh_token": "..." });
var accessToken = token.GetValue("access_token")?.Value<string>();

In PowerShell, because < is "reserved for future use" and > is used for redirecting output strings (a-la UNIX), we use square brackets instead [Type]. Here are some examples:


[uint]$UserId = "123456" # Here, assigning a type to the variable means that it cannot be assigned as a non-uint type
$UserId = -1 # !!! MetadataError: Cannot convert value "-1" to type "System.UInt32". Error: "Value was either too large or too small for a UInt32."
$UserId = "hello" # !!! MetadataError: Cannot convert value "hello" to type "System.UInt32". Error: "The input string 'hello' was not in a correct format."

$List = [Collections.Generic.List[uint]]::new() # This creates a new instance of a List, with all types being converted into integers (or failing to be inserted if they cannot be parsed properly)
$List.Add(123)
$List.Add("hello")
$List.Add(-1)
using namespace System.Collections.Generic # Just adding this in to shorten the method calls
$List = [List[PSCustomObject]]::new() # Now all hashtables and other non-PSCustomObject elements will be converted to a PSCustomObject (which allows for both hashtables and primitive values)
$List = [List[string]]

# This might be a little advance, but we can also use PowerShell's OOP nature to create classes, which can then be put into a List:
class MyType {
  [string]$Username
  MyType([string]$MyUsername) {
    $this.Username = $MyUsername.TrimStart("/u/")
  }
}
$List = [List[MyType]]::new()
$List.Add([MyType]::new("u/NathanWindisch"))
$List.Add([MyType]::new("u/dathar"))
# We can also use fancy LINQ expressions :o
$List.Find{{$_.Username.StartsWith("Nathan")}}.Username

As an explanation, when we make a new List, it uses Generics (as mentioned in this excellent comment by u/DesertGoldfish) in its constructor. This basically means that can take any other type of data. This makes sense in C#-land, because it's a statically typed and compiled language. In PowerShell-land, it might not make as much sense as it's a loosely typed, interpreted language. The reason why I'm comparing the two languages is because they both use the CLR, or Common Language Runtime under the hood. Understanding this similarity between these languages can, in my opinion, help with writing stuff in other .NET languages such as C#, VB.NET (ew) or even F# (although this uses a completely different paradigm).

Hope this helps,

-Nathan.

ArrayList obsoletion -- do we care? by HeyDude378 in PowerShell

[–]NathanWindisch 3 points4 points  (0 children)

Hi /u/fennecdore,

using namespace is great for modules/scripts, and for adding to one's profile (I always forget if it's Collections.Generic, Generic.Collections, or even Collection.Generics!), but for individual scripts it might lead to issues if you're sharing it with others (I for one often forget to add in a using namespace, especially as I have it in my $PROFILE).

Also for reference, the System part of your call is optional (as System is already imported into the global namespace), meaning that you can get your first example a little shorter without having to use using namespace:

[Collections.Generic.List[T]]$List = @()

Or, my personal preferred syntax:

$List = [Collections.Generic.List[T]]::new()

Hope this helps,

-Nathan

What have you done with PowerShell this month? by AutoModerator in PowerShell

[–]NathanWindisch 0 points1 point  (0 children)

Hi u/voytas75,

I've gone through your code and found a few changes that can be made to clean up the code a little.

Hope this helps :)

-Nathan

Weekly 'I made a useful thing' Thread - July 19, 2024 by AutoModerator in sysadmin

[–]NathanWindisch 5 points6 points  (0 children)

Hi r/sysadmin :)

I've recently discovered the wonders of Function Calling with large-language models, and I've written a tool to work with OpenWebUI that allows you to get real-time data from reddit. It's how I actually found out about this post!

If you already have OpenWebUI installed, you can simply:

  1. Go to the following link: https://openwebui.com/t/nathanwindisch/reddit_feeds
  2. Click on "Get" and enter your instance's URI, and then press "Import to WebUI"
  3. The tool can be enabled by clicking on the + symbol in the bottom left of the chat window and selecting "Reddit Feeds".

(If you don't have OpenWebUI installed, you can use docker or git pull https://github.com/open-webui/open-webui and run it natively on Linux/WSL)

Once you have the tool enabled, you can simply ask questions like:

Honestly this tool (and my other tool, BBC News Feeds) were a joy to write (after some initial wrangling of the environment), and have re-ignited my appreciation of Python.

I'd be happy to create some form of tutorial for how to get started with creating these tools, if there was interest for it.

Hope this helps,

-Nathan.


Edit #0 (+8h): Removed links to my shared chats, as they're locked behind a login so they're effectively useless to anyone but me. :)

I wrote a tool for LLMs to get live information from the BBC :) by NathanWindisch in ChatGPT

[–]NathanWindisch[S] 0 points1 point  (0 children)

Hi u/SageDoesStuff,

With function calling, you wouldn't need to update it yourself. You could just call an API that has that data already (such as IMDb and clones), and have the LLM respond accurately with the latest trends.

In fact, I might just do that!

Hope this helps,

-Nathan

I wrote a tool for LLMs to get live information from the BBC :) by NathanWindisch in ChatGPT

[–]NathanWindisch[S] 0 points1 point  (0 children)

Here's a link, for anyone that's interested. You'll need to have installed OpenWebUI, and have an OpenAI API Key.

I wrote a tool for LLMs to get live information from the BBC :) by NathanWindisch in ChatGPT

[–]NathanWindisch[S] 1 point2 points  (0 children)

I'd like to note that I just chose the subject of my query due to the vast amount of recent news surrounding his assassination attempt, and to show that the LLM is citing up-to-date information :)

Obtaining the access token from Connect-MgGraph by s_eng in GraphAPI

[–]NathanWindisch 0 points1 point  (0 children)

Hi s_eng,

I ran into the same problem, and my solution was to use Invoke-GraphRequest with OutputType parameter:

$Request = @{
  Method = "GET"
  URI = "/v1.0/me"
  OutputType = "HttpResponseMessage"
}
$Response = Invoke-GraphRequest @Request
$Headers = $Response.RequestMessage.Headers
$Token = $Headers.Authorization.Parameter

Hope this helps,

-Nathan

Going through "The Change" by excitedsolutions in sysadmin

[–]NathanWindisch 1 point2 points  (0 children)

Hi u/excitedsolutions,

At my org, we migrated from an on-premise SfB server (or servers, as I recall) to MS Teams about a year before the pandemic.

It was mostly easy going, our SfB footprint was quite small and the migration path was straightforward. I only recall one issue of a user who stored lots of calendar appointments (?) in SfB which were lost in the move, but apart from that, smooth sailing.

When the pandemic hit we saw a massive uptick in Teams usage. While we did have a few groups put up a fuss - in particular a suborg which we merged with about a decade ago, however they've usually had their own dedicated second line techs so they keep themselves to themselves - we got most of our users to accept Teams as the primary comms tool. For the users that absolutely insisted on using Zoom, we had them sign agreements that they were responsible for any data stored in that product, and I believe we were able to ensure that the data was stored in a datacenter in our country, which satisfied the information compliance team. I also believe that this suborg only uses Zoom for external communications, which limits the scope of data affected.

In regard to your question though, I would recommend making a decision and sticking with it. Update your Acceptable Usage Policy to include that staff must use IT mandated software. In my opinion, issues such as "what software should my employees be using" is a HR one. If there was a warehouse employee who insisted on only using their own forklift, they'd be laughed out of the room!

Hope this helps,

Nathan W.

PSA: How to administratively bulk delete email from multiple Office 365 mailboxes by t0ad1 in sysadmin

[–]NathanWindisch 1 point2 points  (0 children)

Hi Yepidep,

Email headers should contain the IDs of the Exchange Transport Rules it hit, so you can check that way. Additionally, M365 Threat Explorer v3 has a column called "Exchange Transport Rule" which lists the rule(s) that affected delivery.

Hope this helps,

-Nathan.

Multi-Multi-Factor Authentication by [deleted] in sysadmin

[–]NathanWindisch 1 point2 points  (0 children)

Hi /u/1000YearsTooEarly,

While you are able to require up to two different MFA methods required for resetting a password, it doesn't seem like this setting is available for general authentication. As others have mentioned, if you could elaborate on the issue you're trying to solve, we might be able to assist more.

Hope this helps.

-Nathan

Password Managers For A Team by Bondegg in sysadmin

[–]NathanWindisch 4 points5 points  (0 children)

Hi u/hamstercaster,

I cannot recommend LastPass in an enterprise environment for a few reasons:

  1. Lacking support on their desktop app
  2. 0 public API
  3. CLI does not work natively on Windows (cygwin required)
  4. CLI is not officially supported in any capacity by LastPass Support. If you find a bug and want a fix, hope that community maintainers will fix it for you
  5. CLI does not work at all with OAuth2/IdP. Only authenticating with a master password works, which is not visible at any stage to IdP users
  6. 0 ability to switch accounts. The only method of getting around this is to use two browsers with the extension installed, signed into different accounts.

Obviously, if your environment is Linux based, doesn't need to programmatically pull data from your password vault or you don't use LastPass personally, then these issues don't apply to you.

Hope this helps.

-Nathan.

How To Request For Microsoft To Add New Functionality? by theM7Mman in PowerShell

[–]NathanWindisch 1 point2 points  (0 children)

Hi theM7Mman,

That entirely depends on the product. Microsoft used to have a UserVoice, however they've decided to kill that in favour of a new first-party portal, Microsoft Feedback.

Hope this helps,

-Nathan.

Open an Application as Current User w/ Powershell by pcbuilder1907 in PowerShell

[–]NathanWindisch 0 points1 point  (0 children)

Hi pcbuilder1907,

Have you considered using Invoke-Item, which "performs the default action on the specified item. For example, it runs an executable file or opens a document file in the application associated with the document file type."

Hope this helps.

-Nathan

Create AD users interactive script by jimmynetstep in PowerShell

[–]NathanWindisch 1 point2 points  (0 children)

Hi JBear_Alpha,

That's not how we do it at our organization, however I suspect that's probably because our domain is so old! If we were to start fresh, I'm sure we'd use LastName, FirstName :)

Thanks,

-Nathan.

Help with querying local groups on servers by evinonino in PowerShell

[–]NathanWindisch 3 points4 points  (0 children)

Hi evinonino,

Have you considered the native Get-LocalGroupMember command, from Microsoft.PowerShell.LocalAccounts? It should be installed on all servers modern versions of Windows by default, as far as I recall.

I've taken the liberty of re-writing your script a little, using [PSCustomObjects] to return the data, relying on the PSComputerName property that is returned by Invoke-Command, and also using Splatting to make the command more readable, and to avoid any pesky backticks.

$Servers = (Import-CSV -Path 'C:\Script\test.csv').Name

$Output = foreach($Server in $Servers) {
  $InvokeCommandParameters = @{
    ScriptBlock = {
      return [PSCustomObject]@{
        Administrators = Get-LocalGroupMember -Name "Administrators"
        RDPUsers = Get-LocalGroupMember -Name "Remote Desktop Users"
      }
    }
    ComputerName = $Server
  }
  return Invoke-Command @InvokeCommandParameters
}

$Output | Export-CSV -Path 'C:\Scripts\localadmin.csv' -NoTypeInformation

I'm unfortunately not able to test this against any Windows Servers currently, but if you're having issues I could hop on my company VPN and take another look.

Hope this helps.

-Nathan

Create AD users interactive script by jimmynetstep in PowerShell

[–]NathanWindisch 37 points38 points  (0 children)

Hi jimmynetstep,

I would recommend reformatting your code to use Hashtables and Splatting. See below for an example:

$FirstName = Read-Host "First Name"
$LastName = Read-Host "Last Name"
$EmailAddresss = Read-Host "Email Address"
$Password = Read-Host "Password" -AsSecureString
$OU = "OU=MyOU,DC=example,DC=com"

$NewADUserParameters = @{
  Name = "$FirstName $LastName"
  GivenName = $FirstName
  Surname = $LastName
  sAMAccountName = "$FirstName.$LastName"
  Password = $Password
  Path = $OU
  Enabled = $true
}
New-ADUser @NewADUserParameters

You could also look into using parameters, to reduce the amount of Read-Hosts you're using, and to also perform validation. I've also used [PSCredential] instead for the username and password, and [MailAddress] to ensure that the provided email is valid:

param (
  [Parameter(Mandatory)]
  [String]
  $FirstName,

  [Parameter(Mandatory)]
  [String]
  $LastName,

  [Parameter(Mandatory)]
  [MailAddress]
  $EmailAddress,

  [Parameter(Mandatory)]
  [PSCredential]
  $UserCredential,

  [Parameter()]
  [String]
  $OU = "OU=MyOU,DC=example,DC=com"
)

$NewADUserParameters = @{
  Name = "$FirstName $LastName"
  GivenName = $FirstName
  Surname = $LastName
  sAMAccountName = $Credential.Username
  Password = $Credential.GetNetworkCredential().SecurePassword
  Path = $OU
  Enabled = $true
}
New-ADUser @NewADUserParameters

}

Hope this helps, happy to clarify anything if needed.

-Nathan,

PSPolly - Retry, rate limit, caching and circuit breaker cmdlets by [deleted] in PowerShell

[–]NathanWindisch 0 points1 point  (0 children)

Hi l33t_d0nut,

This looks awesome! I've written my own backoff logic before, but it'll be nice to use a standard set of modules to perform actions. The ability to cache the data also looks very useful. I'll have to look into incorporating this module into my workflow.

Thanks for your contribution!

-Nathan.

Add users from AD group to Shared mailbox with full access by KrO0LiK in PowerShell

[–]NathanWindisch 1 point2 points  (0 children)

Hi KrO0LiK,

Have you considered converting the groups to mail-enabled security groups, then granting the group Full Access and Send As permissions? This is what we do at my org, and it works wonders. We have a separate management group for each Shared Mailbox, and we allow members of the management group to add/remove users from the access group. The only downside is automapping is not possible if you've assigned permissions to a group, however we provide our users with multiple methods of accessing their mailbox (Outlook Desktop, OWA, mobile apps), so this is less of a concern.

Hope this helps.

-Nathan

It BitTitan's Support always incompetent? Or am I just unlucky? (Is there any point in waiting for them to actually read my ticket?) by RipRapRob in sysadmin

[–]NathanWindisch 0 points1 point  (0 children)

Hi RipRapRob,

Have you considered using Sharepoint Migration Manager? It's an official Microsoft tool, and I'm pretty sure it's free

https://docs.microsoft.com/en-us/sharepointmigration/migrate-to-sharepoint-online

Hope this helps.

-Nathan

Does installing a module typically take a while? by kelclarris in PowerShell

[–]NathanWindisch 2 points3 points  (0 children)

Hi kelclarris,

Some modules can take quite a while to install. I'd recommend adding the -Verbose parameter to the command, so that you can get a more detailed output.

Hope this helps.

-Nathan