Picture this – you are a systems administrator working at a major banking institution. The security team walks into your office and lets you know that a major update needs to be applied to all of the servers within the institution – not a problem for most organizations, but in the case of a bank, you could have hundreds if not thousands of remote and branch offices. Sure, we can write scripts to copy out the update files and even execute them remotely from our head office – but the problem most ROBO scenarios are ever-changing – with new offices being created and others closing down all the time. Keeping track of server names, IP schemes, etc. can be quite a time-consuming process. Naturally, we want the same updates, patches, and fixes to be deployed everywhere, in the same manner, in order to provide consistency – so having this up to date list available when we need it is key to driving success within our environment.

So what does this have to do with PowerShell?

Since PowerShell’s first birth into the enterprise back in 2006, we have seen many third party and windows applications adopt the simple scripting language. With such a wide range of support it may make sense for you to keep this “location” listing stored within a PowerShell module – allowing you to access the information you need about locations and simply “pipe” other commands to its metadata – allowing us to essentially convert our branch locations into PowerShell objects that we can retrieve from a PowerShell module. Sometimes it’s easier to simply see how this works before it makes sense, so let’s take a look at a simple example…

If we think back to our banking example we can imagine that we may have a lot of branch offices – and offices of different types as well; think of a fully-fledged bank in a city, small bank kiosks in grocery stores, etc. Our first goal will be to take all of the information about our banking locations, their location codes, server names, IP schemes, bank types, etc. and build a cmdlet which will allow us to quickly retrieve this information from a PowerShell Module. To do so we will first need some sort of database or file containing this information. Today I’ll simply use a CSV file, however, you could use any type of data store you like (MSSQL, Txt, etc.) so long as you change the code below in order to get the data out of the file. Below you can see my CSV file and how I’ve structured this data – try to envision your ROBO environment within this structure…

Location ID Name Type City Province Country Domain Controller Name Domain Controller IP Transaction Server Name Transaction Server IP ESX Host Name ESX Host IP 100 Belleville-Main1 Full Belleville Ontario Canada 100-DC 10.100.1.50 100-TS 10.100.1.60 100-ESXi01 10.100.99.200 101 Belleville-Kiosk1 Kiosk Belleville Ontario Canada 101-DC 10.101.1.50 101-TS 10.101.1.60 101-ESXi01 10.101.99.200 110 Toronto-Main1 Full Toronto Ontario Canada 110-DC 10.110.1.50 110-TS 10.110.1.60 110-ESXi01 10.110.99.200 111 Toronto-Main2 Full Toronto Ontario Canada 111-DC 10.111.1.50 111-TS 10.111.1.60 111-ESXi01 10.111.99.200 112 Toronto-Main3 Full Toronto Ontario Canada 112-DC 10.112.1.50 112-TS 10.112.1.60 112-ESXi01 10.112.99.200 113 Toronto-Kiosk1 Kiosk Toronto Ontario Canada 113-DC 10.113.1.50 113-TS 10.113.1.60 113-ESXi01 10.113.99.200 114 Toronto-Kiosk2 Kiosk Toronto Ontario Canada 114-DC 10.114.1.50 114-TS 10.114.1.60 114-ESXi01 10.114.99.200 115 Toronto-Kiosk3 Kiosk Toronto Ontario Canada 115-DC 10.115.1.50 115-TS 10.115.1.60 115-ESXi01 10.115.99.200 120 Ottawa-Main1 Full Ottawa Ontario Canada 120-DC 10.120.1.50 120-TS 10.120.1.60 120-ESXi01 10.120.99.200 121 Ottawa-Kiosk1 Kiosk Ottawa Ontario Canada 121-DC 10.121.1.50 121-TS 10.121.1.60 121-ESXi01 10.121.99.200 122 Ottawa-Kiosk2 Kiosk Ottawa Ontario Canada 122-DC 10.122.1.50 122-TS 10.122.1.60 122-ESXi01 10.122.99.200 130 Montreal-Main1 Full Montreal Quebec Canada 130-DC 10.130.1.50 130-TS 10.130.1.60 130-ESXi01 10.130.99.200 131 Montreal-Main2 Full Montreal Quebec Canada 131-DC 10.131.1.50 131-TS 10.131.1.60 131-ESXi01 10.131.99.200 132 Montreal-Kiosk1 Kiosk Montreal Quebec Canada 132-DC 10.132.1.50 132-TS 10.132.1.60 132-ESXi01 10.132.99.200 133 Montreal-Kiosk2 Kiosk Montreal Quebec Canada 133-DC 10.133.1.50 133-TS 10.133.1.60 133-ESXi01 10.133.99.200 140 Vancouver-Main1 Full Vancouver Britiish Columbia Canada 140-DC 10.140.1.50 140-TS 10.140.1.60 140-ESXi01 10.140.99.200 141 Vancouver-Kiosk1 Kiosk Vancouver Britiish Columbia Canada 141-DC 10.141.1.50 141-TS 10.141.1.60 141-ESXi01 10.141.99.200 142 Vancouver-Kiosk2 Kiosk Vancouver Britiish Columbia Canada 142-DC 10.142.1.50 142-TS 10.142.1.60 142-ESXi01 10.142.99.200 150 NewYork-Main1 Full New York New York United States 150-DC 10.150.1.50 150-TS 10.150.1.60 150-ESXi01 10.150.99.200 151 NewYork-Kiosk1 Kiosk New York New York United States 151-DC 10.151.1.50 151-TS 10.151.1.60 151-ESXi01 10.151.99.200 160 LosAngeles-Main1 Full Los Angeles California United States 160-DC 10.160.1.50 160-TS 10.160.1.60 160-ESXi01 10.160.99.200 170 Dallas-Main1 Full Dallas Texas United States 170-DC 10.170.1.50 170-TS 10.170.1.60 170-ESXi01 10.170.99.200 171 Dallas-Kiosk1 Kiosk Dallas Texas United States 171-DC 10.171.1.50 171-TS 10.171.1.60 171-ESXi01 10.171.99.200

As you can see above I have a lot of metadata built around all of the different bank locations, however this data as it is isn’t that useful to me when trying to run other PowerShell cmdlets against it– so let’s take this data and create PowerShell module around it, with a Get-BranchLocation cmdlet to return the data to us…

Today we will just be using a simple script module, however, you could use any PowerShell module type you wish – but to get up and running quickly simply create the folder structure shown inside of your C:\Windows\System32\WindowsPowerShell\v1.0\Modules directory, complete with our PSM1 file (the module file) and our locations.csv location listing.

Once the structure is ready it’s time to get started on the code. Our example for today only contains one function (Get-Bank Line 2 through 32) but will give us the foundation for building other types of cmdlets within our module. For simplicity sake, we can see all of the code below – with the line by line explanations below it…

function Get-Bank { param ( [string]$LocationID, [string]$Type, [string]$City, [string]$Province, [string]$Country ) $banks = Import-CSV C:\Windows\System32\WindowsPowerShell\v1.0\Modules\GlobalBankInc\locations.csv $filter = "1 -eq 1" $ParameterList = (Get-Command -Name $MyInvocation.InvocationName).Parameters; foreach ($key in $ParameterList.keys) { $var = Get-Variable -Name $key -ErrorAction SilentlyContinue; if($var) { if ($($var.value) -ne '') { $filter = $filter + " -and `$_."+$var.name+" -eq `"" + $var.Value+"`"" } } } $command = '$banks | Where-Object {'+$filter+' }' return (Invoke-Expression $command) } Export-ModuleMember Get-GlobalBankInfo, Get-Bank 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 function Get - Bank { param ( [ string ] $ LocationID , [ string ] $ Type , [ string ] $ City , [ string ] $ Province , [ string ] $ Country ) $ banks = Import - CSV C : \ Windows \ System32 \ WindowsPowerShell \ v1 . 0 \ Modules \ GlobalBankInc \ locations . csv $ filter = "1 -eq 1" $ ParameterList = ( Get - Command - Name $ MyInvocation . InvocationName ) . Parameters ; foreach ( $ key in $ ParameterList . keys ) { $ var = Get - Variable - Name $ key - ErrorAction SilentlyContinue ; if ( $ var ) { if ( $ ( $ var . value ) - ne '' ) { $ filter = $ filter + " -and `$_." + $ var . name + " -eq `" " + $var.Value+" ` "" } } } $ command = '$banks | Where-Object {' + $ filter + ' }' return ( Invoke - Expression $ command ) } Export - ModuleMember Get - GlobalBankInfo , Get - Bank

Line 4 through 9 – These are our function/cmdlet parameters – meaning we define these in order to allow our users to pass information into our cmdlet. Here we have 5; LocationID, Type, City, Province, and Country – all matching with column headers in our CSV file. It’s the values of these parameters that can be passed in order to filter our result set.

Line 12 – This simply imports our CSV file of our branch locations into the banks variable.

Line 14 – Here we establish the beginning of our filtering sequence. Since the parameters of this function are not required, meaning we can pass a city value, a province value, a city and province value, or in fact no parameters at all, we have to dynamically build our filter. By beginning our filter with an always true “1 –eq 1” sequence we can make the remaining code much easier to write.

Line 16 – This line is used to gather all of the parameters which were passed to the cmdlet.

Line 18 through 31 – This loops through the passed parameters and if it finds a parameter with a value it is appended to our filter string on Line 26.

Line 32 – This takes the command which we would like to run and appends the filter string to it.

Line 33 – Here we complete our function and return the evaluated expression of our command string.

Line 36 – In order to use our Get-Bank cmdlet outside of this module, we need to ensure we export it as a module member.

Now if we head into our PowerShell console and run our new cmdlet, you should see some similar output as that below…

So by now, you might be thinking “How can such a small little function help me with managing my branch locations?” Well, take for instance our example of copying out a patch to all of the domain controllers – In order to do this utilizing our new cmdlet we could do the following

Get-Bank | foreach-object { Copy-Item c:\super-patch.exe \\$($_.DomainControllerName\share$\ }

Need to enable ssh on your ESXi hosts which are located only in kiosk branches – no problem

Get-Bank –Type Kiosk | foreach-object { Get-VMHost –Name $($_.ESXHostName) –User username –Password password | Start-VMHostService –HostService ($_ | Get-VMHostService | Where {$_.Key –eq “TSM-SSH”} }

How about restarting all of the Transaction Services located in Quebec?

Get-Bank –Province Quebec | foreach-object { Restart-Computer –ComputerName $($_.TransactionServerName) }

By now we can really see the efficiencies and consistencies that bundling up our remote/branch offices into a cmdlet with a PowerShell module can bring – and this is just with one simple cmdlet. Certainly, this opens the doors for much more. If we take more of the mundane, repetitive tasks we perform at each location, script them into PowerShell, and simply add them into a function/cmdlet into our PowerShell module we not only make our lives easier by automating our work but down the road when things go wrong, we should be left with a more consistent environment – which we all know makes troubleshooting easier! For now, give PowerShell a shot at managing those remote locations for you, stop wasting time looking up hostnames and IPs, and just Get-Scripting!

Related materials:

PowerShell Modules – Why bother?

5 tips to help you explore the world of PowerShell scripting

Views All Time Views All Time 4 Views Today Views Today 7

Appreciate how useful this article was to you? No Ratings Yet

No Ratings Yet

Loading... Loading...