Contact

Subscribe via Email

Subscribe via RSS/JSON

Categories

Creative Commons Attribution 4.0 International License
© Rakhesh Sasidharan

Elsewhere

Note to self: PowerShell can do JSON and Invoke-WebRequest for REST API calls

I am so bummed at myself! Proud, but also bummed. 

At work we are doing some migration work and the vendor we are migrating data to has a REST API which we can talk to using curl and pass data as JSON. I spent the last two weeks creating various bash scripts that can send and receive JSON and while I did a good job (in my opinion), and learnt a lot of things (discovered jq for instance, it’s amazing!), and it was a great working with bash and sed and awk and all these *nix tools after such a long time (and all this was done on the macOS this time, so was a good way to send time on the macOS CLI too) … I now realize that doh PowerShell supports JSON and I could have used Invoke-WebRequest for all my curl calls, so I could have done the whole work in PowerShell … a much more familiar environment! In the process I could have saved some time and taken a lot less stress.

That’s why I am bummed. I am proud I did a good, but I also kind of wish I had been more aware of what PowerShell can do and taken the effort to Google a bit about it. 

Thing is I have a huge soft corner for bash and all these things, so I know it’s my internal bias that just pushed me to jump at the opportunity and work with this rather than check out PowerShell. I do love me bash and sed and all those. :)

VPN client over-riding DNS on macOS

Spent a lot of time today with this. Such an irritating topic! Primarily coz there doesn’t seem to be much info on how to do this correctly.

I have blogged about this in the past, in an opposite that. That time once I connect via VPN my macOS wasn’t picking up the DNS servers offered by VPN. That was a different VPN solution – the Azure Point to Site VPN client. Since then I have moved to using GlobalProtect and that works differently in that it over-rides the default resolvers and makes the VPN provided ones the primary.

Here was my DNS configuration before connecting to VPN:

Once I connect via GlobalProtect these change:

And I have no idea how to change the order so that my home router stays at #1 and the VPN provided one is added as #2.

Initially I thought the “order” in the DNS configuration might play a role. So I tried something changing the order of my home router to be better than the VPN one. I tried both setting it to a larger and smaller number, neither worked.

This is how one can try to change the order:

Didn’t help.

As an aside, don’t use tools like ping or nslookup to find how your DNS resolution is working. From this StackOverflow article which I’d like to copy paste here:

macOS has a sophisticated system for DNS request routing (“scoped queries”) in order to handle cases like VPN, where you might want requests for your work’s domain name to go down your VPN tunnel so that you get answers from your work’s internal DNS servers, which may have more/different information than your work’s external DNS servers.

To see all the DNS servers macOS is using, and how the query scoping is set up, use: scutil --dns

To query DNS the way macOS does, use: dns-sd -G v4v6 example.com or dns-sd -q example.com

DNS-troubleshooting tools such as nslookup(1), dig(1), and host(1) contain their own DNS resolver code and don’t make use of the system’s DNS query APIs, so they don’t get the system behavior. If you don’t specify which DNS server for them to use, they will probably just use one of the ones listed in /etc/resolv.conf, which is auto-generated and only contains the default DNS servers for unscoped queries.

Traditional Unix command-line tools that aren’t specific to DNS, such as ping(8), probably call the traditional gethostbyname(3) APIs, which, on macOS, make use of the system’s DNS resolver behaviors.

To see what your DHCP server told your Mac to use, look at the domain_name_server line in the output of: ipconfig getpacket en0

 

So ping is probably fine but nslookup and dig are definitely a no-no.

Anyways, in my case I finally decided to do remove the DNS entries provided by VPN altogether and replace it with my home router DNS. I’d have to do this each time I reconnect to VPN, but that can’t be helped I guess. If I launch scutil from the command line and look at the list of services and their DNS settings I can identify the one used by GlobalProtect.

I just chose to over-ride both the SearchDomain and ServerAddresses with my local settings (thanks to this post and this):

For my own copy paste convenience for next time, here’s what I would have to do once I launch scutil:

Ok, so far so good. But what if I also want resolution to the VPN domains working via VPN DNS servers when I am connected? Here I go back to what I did in my previous blog post. I create multiple files under /etc/resolver for scoped queries, each having different search_order (queries to internal DNS have a lower search_order and a timeout; queries to external DNS have a higher search_order).

Update: Turns out GlobalProtect over-writes the DNS settings periodically. So I made a script as below in my home directory:

And put it in my crontab:

 

PowerShell snippet to get the name of each attached monitor

Needed to create this for a colleague. Get the names of attached monitors via WMI/ PowerShell. 

The Get-WmiObject WmiMonitorID -Namespace root\wmi cmdlet returns output like this for each attached monitor:

The Name etc. is in ASCII code so we have to take the numbers, convert to [char], and join them to get the name. Here’s what it looks like. I have to remove the 0 and concatenate the rest.

So that’s what the first code snippet does. At the end of the pipeline I do a -join “;” because my colleague wanted it semi-colon separated per monitor but that’s optional. 

PowerShell: listing snap-ins and their cmdlets

I know what to do when it comes to finding a list of available modules in PowerShell (Get-Module -ListAvailable) and a list of cmdlets in each module (Get-Command -Module <name>). But I don’t use snap-ins much and so the equivalent for that isn’t always available on my fingertips. So this blog post is a reminder to future myself:

To list all registered snap-ins:

And to find the cmdlets in a particular snap-in:

Of course replace -match with -eq if you know the snap-in’s exact name.

Update: I am not sure (coz I don’t recollect my steps) but maybe I need to do an Add-PSSnapin <name> first before Get-Command.

Using PowerShell to change a scope option across multiple scopes & multiple servers

I had to change option 150 (Cisco VoIP) for multiple scopes across multiple servers as we are moving our Call Manager to a new location this weekend, and couldn’t be bothered doing it manually post move.

All my voice scopes have the word Voice or VoIP in them so I match on them. A lot of the code is verbose coz I like to be a bit verbose, but you could probably crunch it all down to a single line or two. :)

Changing UPN suffix for all users in a group

Simple PowerShell one-liner –

The "$OldUPN -> $NewUPN";  can be skipped. That’s just for me to get output of the changes being done.

Using PowerShell to find Computer objects in AD that have inheritance disabled

I needed to find the computer objects in an AD OU that had inheritance disabled. Did the following:

And to extend this to enable inheritance on the affected objects:

Using PowerShell to rename folders and change ACLs

Here’s something I had to do at work a few weeks back. I wanted to blog about it since then but never got around to it.

We had copied a bunch of folders from one location to another. Since this was a copy the folders lost their original ACLs. I wanted to do two things – 1) the folder names were in the format “LastName, FirstName” and I wanted to change that to “username” (I had a CSV file with mappings so I could use that to do the renaming). 2) I wanted to change the ACLs so the user had modify rights to the folders.

For the first task here’s what I did:

Note that apart from renaming I also move the folder to a different path (coz I had multiple source locations and wanted to combine them all into one).

For the second task here’s what I did:

Later on I realized the folders still had the BUILTIN\Users entity with full control so I had to remove these too. The code for that was slightly different so here goes:

This is a good article on what I was doing above. And this TechNet article is a useful resource on the various rights that can be assigned.

Find all GPOs modified yesterday

Via PowerShell, of course:

And to make a report of the settings in these same GPOs:

Yeah, I cheated in the end by using > rather than Out-File. Old habits. :)

Not sure why, but doing a search like Get-GPO -All | ?{ ($_.ModificationTime) -eq [datetime]"18 September 2017" } doesn’t yield any results. I think it’s because the timestamps don’t match. I couldn’t think of a way around that.

PowerShell – Find all AD users with ACL inheritance disabled

Quick one-liner to find all AD user objects with ACL inheritance disabled:

Another one:

 

Scanning for MS17-010

Was reading about the WannaCrypt attacks. If you have the MS17-010 bulletin patches installed in your estate, you are safe. I wanted to quickly scan our estate to see if the servers are patches with this. Not my job really, but I wanted to do it anyways. 

The security bulletin page lists the actual patch numbers for each version of Windows. We only have Server 2008 – 2016 so that’s all I was interested in. 

Here’s a list of the Server name, internal version, and the patch they should have.

  • Server 2008 | 6.0.6002 | KB4012598
  • Server 2008 R2 | 6.1.7600 | KB4012215 or KB4012212
  • Server 2012 | 6.2.9200 | KB4012214 or KB4012217
  • Server 2012 R2 | 6.3.9600 | KB4012213 or KB4012216
  • Server 2016 | 10.0.14393 | KB4013429

One thing to bear in mind is that it’s possible a server doesn’t have the exact patch installed, but is still not at any risk. That is because since October 2016 Windows patches are cumulative. So if you don’t have the particular March 2017 patch installed, but do have the April 2017 one, you are good to go. The numbers above are from March 2017 – so you will have to update them with patch numbers of subsequent months too to be thorough. 

Another thing – I had one server in my entire estate where the patch above was actually installed but turned up as a false positive in my script. Not sure why. I know it isn’t a script issue. For some reason that patch wasn’t being returned as part of the “Win32_QuickFixEngineering” output. Am assuming it wasn’t installed that way on this particular server.

Without further ado, here’s the script I wrote:

That’s all. Nothing fancy. 

Go through a group of servers and find whether a particular patch is installed

Patch Tuesday is upon us. Our pilot group of server was patched via SCCM but there were reports that 2012R2 servers were not picking up one of the patches. I wanted to quickly identify the servers that were missing patches. 

Our pilot servers are in two groups. So I did the following:

The first two lines basically enumerate the two groups. If it was just one group I could have replaced it with Get-ADGroupMember "GroupName"

The remaining code checks whether the server is online, filters out 2012 R2 servers (version number 6.3.9600), and makes a list of the servers along with the installed date of the hotfix I am interested in. If the hotfix is not installed, the date will be blank. Simple. 

Oh, and I wanted to get the output as and when it comes so I went with a Width=20 in the name field. I could have avoided that and gone for an -AutoSize but that would mean I’ll have to patiently wait for PowerShell to generate the entire output and then Format-Table to do an autosize. 

Update: While on the Win32_QuickFixEngineering WMI class I wanted to point out to these posts: [1], [2]

Worth keeping in mind that Win32_QuickFixEngineering (or QFE for short) only returns patches installed via the CBS (Component Based Servicing) – which is what Windows Updates do anyway. What this means, however, is that it does not return patches installed via an MSI/ MSP/ MSU. 

Reboot a bunch of ESXi hosts one after the other

Not a big deal, I know, but I felt like posting this. :)

Our HP Gen8 ESXi hosts were randomly crashing ever since we applied the latest ESXi 5.5 updates to them in December. Logged a call with HP and turns out until a proper fix is issued by VMware/ HPE we need to change a setting on all our hosts and reboot them. I didn’t want to do it manually, so I used PowerCLI to do it en masse.

Here’s the script I wrote to target Gen8 hosts and make the change:

I could have done the reboot along with this, but I didn’t want to. Instead I copy pasted the list of affected hosts into a text file (called ESXReboot.txt in the script below) and wrote another script to put them into maintenance mode and reboot one by one.

The screenshot output is slightly different from what you would get from the script as I modified it a bit since taking the screenshot. Functionality-wise there’s no change.

Windows Services – Fix unquoted path vulnerabilities using PowerShell

At work as part of some security certification we are running Nessus scans on all our systems and it came up with the following vulnerability – link. Read that link, it’s good info.

Basically if one of your Windows Service entries point to (say) “C:\Windows\Microsoft.NET\Framework64\v3.0\Windows Communication Foundation\SMSvcHost.exe” without the double quotes then one could potentially create a malicious file called Windows.exe at “C:\Windows\Microsoft.NET\Framework64\v3.0\Windows” and Windows will execute that file instead of parsing the full path and treating it as part of a folder name. That’s because Windows uses space as a delimiter between a command and its switches & arguments and so it could treat the entry as “C:\Windows\Microsoft.NET\Framework64\v3.0\Windows.exe” with arguments “Communication Foundation\SMSvcHost.exe“.

The solution for this is to find all such entries that contain a space, and if the path is not in double quotes then make it so. You have to do this in the registry, so you could either do it manually or make a script and do it en masse. I went the latter route so here’s something I created.

I am being lazy and not really offering input etc as I just expect a list of servers to be scanned in a file called “ServerNames.txt”. I have the above saved to a .ps1 file and I simply run it as .\Registry.ps1. Feel free to adapt to your needs.

What it does is that it connects to the server specified (provided they are online), tries to open the “services” key under HKLM (assuming it has access), and then enumerates all the subkeys that contain the service names and checks if the path has a space. It only matches against paths containing a .exe so it could miss out some stuff. Once it finds a match it extracts the bit up to the .exe, splits it along any spaces, and if there are more than one results (which means the path did have spaces) it encloses it in double quotes and replaces the original entry.

The code is smart enough to know it must correctly double quote something like "D:\Program Files (x86)\BigHand\BigHand Workflow Server 4.6\BHServer.exe /V:4.6" as "D:\Program Files (x86)\BigHand\BigHand Workflow Server 4.6\BHServer.exe" /V:4.6 and not "D:\Program Files (x86)\BigHand\BigHand Workflow Server 4.6\BHServer.exe /V:4.6".

By default it only displays results. An optional parameter -FixIt will also make the changes.

Example output:

Hope it helps!

PowerShell – List of machines with CPU and disk info

Had to come up with a list of machines and their CPU, disk info etc. Thought it better to make a small script for it.

Hope it helps someone.